[SOLVED] Stylize using CSS and editable QComboBox's completions list view
-
i'm not sure if that's intended to work at all. But you can try min-height. If that's not working setting the size of view items is not possible...
-
Hi,
we also had the same problem styling the completer popup and could solve the problem by implementing our own completer class that we derived from QCompleter. The problem seems to be, that the completer popup does not use a QStyledItemDelegate and thus does not support styling of single items. We solved the problem by assigning a QStyledItemDelegate to the item view after the model has been assigned to the completer:
@
/**- Private data class (pimpl)
/
struct CompleterPrivate
{
QStyledItemDelegate CompleterDelegate;
};
CCompleter::CCompleter(QObject* parent)
: QCompleter(parent),
d(new CompleterPrivate())
{
d->CompleterDelegate = new QStyledItemDelegate(this);
popup()->setObjectName("completerPopup");
}CCompleter::~CCompleter()
{
delete d;
}void CCompleter::setModel(QAbstractItemModel* model)
{
QCompleter::setModel(model);
popup()->setItemDelegate(d->CompleterDelegate);
}
@ - Private data class (pimpl)
-
Yes, I've already tried using min-height - doesn't work.
Thank you for the extensive help. I was examining the source code of the QLineEdit and QComboBox to find whether the QAbstractItemView is created there and if so, does it have an object name. But the actual holder of the QAbstractItemView as you've pointed out is the QCompleter, which probably assigns the parent (which is a QWidget subclass) of the QCompleter (which is QObject subclass) to be the parent of the view as well and using QComboBox QAbstractItemView descendant css selector doesn't apply the given stylesheet to the completions list the same way it does for the choices list.
Thanks.
-
Uwe Kindler: thank you, I will try it out. The solution you propose is the same as the one used for enabling stylizing on QComboBox as a whole:
http://stackoverflow.com/questions/13308341/qcombobox-abstractitemviewitem -
well...the subclassing of QCompleter is unnecessary extra work since you already get what you need with the popup() (which is a simple QListView btw.) method.
You can set your delegate also directly there.@
class MyCompleterDelegate : public QStyledItemDelegate
{
public:
MyCompleterDelegate(QObject* parent = 0) : QStyledItemDelegate(parent)
{
}QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); size.setHeight( ... ); return size; }
}
@and set this delegate
@
completer->popup()->setItemDelegate(new MyCompleterDelegate(completer->popup())); //or if you directly set a "empty" QStyledItemDelegate instead of custom deleagte
@thats all ;)
-
I've tried the QCompleter subclass approach and the following css:
So, I presume I should make a Q_PROPERTY, so that I can access this height from css?
I took the subclass approach the same way I've made QComboBox stylable:
@
StylablePopupCompleter::StylablePopupCompleter( QObject* parent )
: QCompleter( parent )
{
this->makePopupStylable();
}StylablePopupCompleter::StylablePopupCompleter( QAbstractItemModel* model, QObject* parent )
: QCompleter( model, parent )
{
this->makePopupStylable();
}#ifndef QT_NO_STRINGLISTMODEL
StylablePopupCompleter::StylablePopupCompleter( const QStringList& completions, QObject* parent )
: QCompleter( completions, parent )
{
this->makePopupStylable();
}
#endifStylablePopupCompleter::~StylablePopupCompleter()
{
}void StylablePopupCompleter::makePopupStylable()
{
QAbstractItemView* const completionsView = this->popup();
completionsView->setItemDelegate( new QStyledItemDelegate( completionsView ) );
}@
-
Well, I thought my example was quite clear (clear like german Klossbruehe) and you just needed to copy my code. So here we go again:
You can only style classes that are derived from QWidget - so no - you can't style QCompleter directly - never
You can style the QCompleter popup because it is an QAbstractItemView (derived from QWidget)
To style the popup (the QAbstractItemView) you need a CSS selector to style only the completer popups
That was the reason I gave the popup the object name "completerPopup"
Now you can use CSS to stlye all QAbstractItemViews with name "completerPopup"
You need to set the item delegate after the model has been set.
You need to set the item delegate each time a new model is assigned because it seems that internally a new item view or delegate is created if a new model is assigned
This was the reason I set the delegate in the setModel() function because this ensures that each time a new model is assigned, the item delegate will be updated.
The solution from raven-worx is not what you want because it sets the height hardcoded in the delegate and is not stylable via CSS.
C++ Code:
@ /**
* Private data class (pimpl)
/
struct CompleterPrivate
{
QStyledItemDelegate CompleterDelegate;
};CCompleter::CCompleter(QObject* parent) : QCompleter(parent), d(new CompleterPrivate()) { d->CompleterDelegate = new QStyledItemDelegate(this); popup()->setObjectName("completerPopup"); } CCompleter::~CCompleter() { delete d; } void CCompleter::setModel(QAbstractItemModel* model) { QCompleter::setModel(model); popup()->setItemDelegate(d->CompleterDelegate); }
@
Example CSS Stylesheet:
@
QAbstractItemView#completerPopup
{
border: 1px solid rgb(81, 81, 81);
padding: 1px;
}QAbstractItemView#completerPopup::item
{
padding-top: 2px;
padding-bottom: 2px;
}
@ -
bq. That was the reason I gave the popup the object name “completerPopup”
If you have looked better in my code you will notice that the class is named:
StylablePopup Completer not StylableCompleter - since only the visual element is stylable. And I know QWidget-based classes are stylizable only.About the setModel - thank you for the remark, since changing the model, changes the delegate as well.
-
I think you misunderstood the meaning of object name. Object name does not mean class name - so it does not matter if you name your class StylablePopupCompleter, StylableCompleter or FlyingPigCompleter. Object name means that you call the method setObjectName of the popup to give all popups an object name that you can use from CSS as ID selector.
C++ Code:
@popup()->setObjectName("completerPopup");@
Now you can use the CSS ID selector to style all QAbtractItemViews whose object name is completerPopup.
CSS Code:
@QAbstractItemView#completerPopup
{
...
}
@bq. So, I presume I should make a Q_PROPERTY, so that I can access this height from css?
Which class should get this Q_PROPERTY?
-
No, I understand the meaning of object name very well, and I know that the object name could be used to access QWidget-based stylable instances through the css. Your remark:
bq. That was the reason I gave the popup the object name “completerPopup”
Targets that you think I want to stylize the QCompleter, not its popup since I've named my QCompleter subclass StylablePopupCompleter. But my point is that the completer has StylablePopup. I don't mean that the QCompleter is stylable but its popup. That's why I haven't named it StylableCompleter but StylePopupCompleter.
@
QAbstractItemView#completerPopup
{
...
}
@You are wrong here.
@
QAbstractItemView #completerPopup
@You use css descendant selector to access the #completerPopup but #completerPopup is not a descendant of QAbstractItemView, it is QAbstractItemView, so raven-worx is correct in this case:
@
QAbstractItemView[objectName="MyCompleterList"] {
...
}
@Thank you for the help.
-
bq. You use css descendant selector to access the #completerPopup but #completerPopup is not a descendant of QAbstractItemView, it is QAbstractItemView, so raven-worx is correct in this case:
You are wrong again. You really should read the Qt CSS documentation ;O):
"http://doc.qt.digia.com/4.7/stylesheet-syntax.html":http://doc.qt.digia.com/4.7/stylesheet-syntax.html
This is was the QT reference says if you follow the link:
bq. ID Selector QPushButton#okButton Matches all QPushButton instances whose object name is okButton.
So you never need to do something like QAbstractItemView[objectName="MyCompleterList"] because you can alway use # to select an QWidget with a certain object name.
Btw. my code was copied from a real "world application":http://www.cetoni.de/products/software/qmixelements.html we have implemented here and therfore I can assure you that it works:
-
guys ... you are both talking about the same thing.
when there is a space before the # is treated as a descendant, otherwise not.
It doesn't matter you both mean the same thing ... i think there is just a misunderstanding with each other ;)Note: using [objectName="XXX"] or #XXX is the same thing ... absolutely no difference.
-
Ah - ok, that was new to me.
Could you please provide a link to the Qt documentation where I can find some details. I have searched the Qt CSS documentation but have not found any place where # is used as a descendant selector.
I only found this one
http://doc.qt.digia.com/4.7/stylesheet-syntax.html
bq. Descendant Selector QDialog QPushButton Matches all instances of QPushButton that are descendants (children, grandchildren, etc.) of a QDialog.
So nothing about # as descendant selector. Strange?!?
-
the # is no descendant selector ... but the space is. # is always the objectName (any widget).
-
Exactly, the strange thing was that:
@
QAbstractItemView #completerPopup
@didn't work but:
@
QAbstractItemView#completerPopup
@worked.
Ok, clarified that case. Sorry, Uwe.
Many thanks Uwe, raven for the extensive and detailed answers.