13

In my application, I want to disable some items (i.e. not selectable, no highlights when mouse hovering above, and the texts are greyed out) in the QComboBox when certain conditions are met.

I indeed found someone did ask the same question here: Disable Item in Qt Combobox But none of these solutions in the answers seem to actually work (including the trick).

Is there a decent and 'correct' way to implement this?

EDIT:

I found out why setting the flags wouldn't disable the items in my application: for some reasons, I had to set the style QStyle::SH_ComboBox_UseNativePopup(see https://codereview.qt-project.org/#/c/82718/). And this setting for some reasons blocked the flag setting. Does anyone have an idea why, and how to work around? A minimum test example is included (modified from the answer of @Mike):

#include <QApplication>
#include <QComboBox>
#include <QStandardItemModel>
#include <QProxyStyle>

class ComboBoxStyle : public QProxyStyle
{
public:
    int styleHint ( StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const override
    {
        if ( hint == QStyle::SH_ComboBox_UseNativePopup )
        {
            return 1;
        }
        return QProxyStyle::styleHint( hint, option, widget, returnData );
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QComboBox comboBox;

    // Setting this style would block the flag settings later on.
    comboBox.setStyle( new ComboBoxStyle() );

    comboBox.insertItem(0, QObject::tr("item1"));
    comboBox.insertItem(1, QObject::tr("item2"));

    QStandardItemModel* model = qobject_cast<QStandardItemModel*>(comboBox.model());
    QStandardItem* item= model->item(1);
    item->setFlags(item->flags() & ~Qt::ItemIsEnabled);

    comboBox.show();
    return a.exec();
}
Community
  • 1
  • 1
Wayee
  • 339
  • 1
  • 4
  • 15
  • did you try [this](http://stackoverflow.com/a/21740341/2666212) answer? if you are not using `setModel` in your `QComboBox` (ie. you are adding your items using `addItem`) this should work for you. – Mike Aug 12 '16 at 09:58
  • Does this answer your question? [Disable Item in Qt Combobox](https://stackoverflow.com/questions/11439773/disable-item-in-qt-combobox) – Romário Feb 05 '20 at 20:22

2 Answers2

28

The answer linked in my comment above seems to be talking about an old version of Qt. I have tested on Qt5.4 and Qt5.6 and there is no need set the color yourself here, you just need to set and/or clear the Qt::ItemIsEnabled flag, here is an example:

#include <QtWidgets>

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  QComboBox comboBox;
  comboBox.addItem(QObject::tr("item1"));
  comboBox.addItem(QObject::tr("item2"));
  comboBox.addItem(QObject::tr("item3"));
  QStandardItemModel *model =
      qobject_cast<QStandardItemModel *>(comboBox.model());
  Q_ASSERT(model != nullptr);
  bool disabled = true;
  QStandardItem *item = model->item(2);
  item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled
                          : item->flags() | Qt::ItemIsEnabled);
  comboBox.show();
  return a.exec();
}
Mike
  • 7,220
  • 1
  • 23
  • 39
  • Note that this relies on undocumented behavior, i.e. casting the backing model to a `QStandardItemModel`. This comes with the same caveats as including private headers. – anonymous Aug 12 '16 at 10:22
  • As an alternative, explicitly create a `QStandardItemModel` instance and set it on the combo box first. – anonymous Aug 12 '16 at 10:24
  • 3
    @JonHarper , No, this is not undocumented, please read [this](https://doc.qt.io/qt-5/qcombobox.html#details). *QComboBox uses the model/view framework for its popup list and to store its items. By default a **QStandardItemModel** stores the items and a QListView subclass displays the popuplist*. – Mike Aug 12 '16 at 10:30
  • 4
    @JonHarper , see the documentation for [`QComboBox::QComboBox(QWidget *parent = Q_NULLPTR)`](https://doc.qt.io/qt-5/qcombobox.html#QComboBox) too. *Constructs a combobox with the given parent, using the default model **QStandardItemModel***. – Mike Aug 12 '16 at 10:32
  • 1
    My apologies. This used to be undocumented. – anonymous Aug 12 '16 at 10:40
  • 1
    Probably still a good defensive move to check `model` is not null after casting, regardless of what the documentation says... – Toby Speight Oct 10 '18 at 07:28
  • @TobySpeight, you are absolutely right, thanks for pointing that out (I added an assert statement) – Mike Oct 10 '18 at 18:28
4

Here is the technique @Mike describes, wrapped up in a convenient utility function:

void SetComboBoxItemEnabled(QComboBox * comboBox, int index, bool enabled)
{
    auto * model = qobject_cast<QStandardItemModel*>(comboBox->model());
    assert(model);
    if(!model) return;

    auto * item = model->item(index);
    assert(item);
    if(!item) return;
    item->setEnabled(enabled);
}
Parker Coates
  • 5,918
  • 2
  • 26
  • 29