Search code examples
cssqtpaddingqcombobox

Why does padding-left style result in QComboBox menu stretching to screen height?


Consider the following example. It creates two instances of QComboBox: one with a stylesheet, and another without. If the first one is clicked (with widget style being Fusion), the menu is sized as expected, although padding of text is inconsistent between hovered and non-hovered items. But if you click on the second one, the padding problem is now fixed, but the menu appears to have huge entries, making the menu fill the whole screen height.

#include <QComboBox>
#include <QApplication>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    QComboBox box1, box2;
    const QString stylesheetOrig=R"(
QComboBox::item:selected
{
    background-color: #0000ff;
}
)";
    box1.setStyleSheet(stylesheetOrig);
    box2.setStyleSheet(stylesheetOrig+R"(
QComboBox::item
{
    padding-left: 27px;
}
)");
    box1.addItems({"Hello 1","Goodbye 1"});
    box2.addItems({"Hello 2","Goodbye 2"});
    box1.show();
    box2.show();

    return app.exec();
}

If I remove the padding statement, still leaving the QComboBox::item {} part, then nothing strange (and nothing useful) happens. But if I even set the padding to 1px or 0px, the stretching already happens with all its might.

Why does setting horizontal padding result in such a strange change vertically?


Solution

  • Wow OK, that is screwy indeed. Adding any css to a combo box makes it go into some other "retro" mode with showing icons next to the current item. I've never noticed that in many years, but I see a bunch of common threads on the issue. Seems to only affect Fusion style though, I was confused for a while on my Windows box until I figured that out.

    The question is if you want the checkbox or not. Here's one way to get rid of it, the only consistent one I found after a bit of playing with it. The main trick is setting the selection colors on the ::item and not on ::item:selected (the latter makes the checkmarks appear).

    QComboBox::item { 
      selection-background-color: #0000ff;
      selection-color: palette(highlighted-text);
    }
    

    enter image description here

    PS. Another reason for confusion and why QComboBox::item and :checked even work is that the QComboBox default item delegate (used to draw the items in the QListView which the combo box uses for the options list) "pretends" it's a QMenu: QComboMenuDelegate::paint()
    So another workaround would be to use something more sane/customizable for a delegate, perhaps even a default QStyledItemDelegate.


    ADDED: A version keeping the checkbox and ensuring the unchecked items have padding (w/out using padding property which appears to be FUBAR when used in a combo box item with Fusion style). The icon size seems easiest set via iconSize property -- I tried a few ways via css icon/image/element width/height but nothing affected it... probably because the iconSize property overrides it.

    QComboBox { qproperty-iconSize: 12px; }       /* or QComboBox::setIconSize() */
    QComboBox::indicator { color: transparent; }  /* to force space for the icon column */
    
    /* Using ::item:selected vs. ::item { selection-*-color: } will apparently make the 
      checkbox column appear... at least with Fusion as the main style */
    QComboBox::item:selected { 
      color: palette(highlighted-text); 
      background-color: #0000ff; 
    }
    

    enter image description here


    VERSION 3 (as per comments):

    QComboBox { qproperty-iconSize: 12px; }       /* or QComboBox::setIconSize() */
    QComboBox::indicator:!checked { border: 0; }  /* to force space for the icon column */
    QComboBox::item { background-color: palette(base); }  /* gets rid of icon|text separator */
    
    /* Using ::item:selected vs. ::item { selection-*-color: } will apparently make the 
      checkbox column appear... at least with Fusion as the main style */
    QComboBox::item:selected { 
      color: palette(highlighted-text); 
      background-color: #0000ff; 
    }
    

    enter image description here

    There's still a 1px frame line at the top of the unselected icon area, though it's pretty subtle. I have no idea where that comes from... tried some guesses but to no avail.