[SOLVED] Stylize using CSS and editable QComboBox's completions list view



  • @
    QListView {
    background: red;
    }
    @

    does the trick, but in very global level. I want to stylize only the list view of the QComboBox completion list. Something like:
    @
    QComboBox QListView,
    QComboBox > QListView,
    QComboBox QLineEdit QListView, /* the combo box's editor */
    QComboBox > QLineEdit > QListView,
    {
    ...
    }
    @

    All of these don't work. Any suggestions how to stylize the QComboBox's completion list view only?


  • Moderators

    are you sure that
    @
    QComboBox QListView {
    ...
    }
    @

    is not working? Because i just tried it and it works. I think you may have another style definition which overrides yours.

    Alternatively you can try to style QComboBoxListView class.



  • @
    QComboBox QListView {
    background: red;
    }
    @

    Stylizes the drop-down of the combobox the same way:
    @
    QComboBox QAbstractItemView {
    ...
    }
    @

    ... does. But I'm trying to stylize the completions list, not the choices list. The title of the topic says:

    bq. Stylize using CSS and editable QComboBox’s completions list view

    ... not the drop down that lists all possible combobox choices. So, when you have a QCompleter set to the combobox and start typing in the combobox, a completions' list is displayed the same way the choices list is displayed. But the completions list is not stylized.


  • Moderators

    ah sorry for that.
    In this case you have to do the following:
    @
    completer->popup()->setObjectName("MyCompleterList");
    @
    and in the stylesheet:
    @
    QAbstractItemView[objectName="MyCompleterList"] {
    ...
    }
    @
    since i see no other styling possibility.
    Note that the popup has no parent set. It's just a widget with the popup window flag set.



  • Bingo. Thanks. One more question:
    @
    QAbstractItemView[objectName="MyCompleterList"]::item {
    height: ...;
    }
    @

    ... doesn't work. Any suggestions?


  • Moderators

    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);
    }
    @



  • 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


  • Moderators

    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();
    }
    #endif

    StylablePopupCompleter::~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:


  • Moderators

    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?!?


  • Moderators

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.