Search code examples
qtqpushbuttonqstyleditemdelegateqicon

How to set QStyleOptionButton like a checkbox with custom icons


I have a custom Delegate class which inherits from QStyledItemDelegate. In its paint() event, I would like to add QStyleOptionButton which should be checkable. Is it possible?

For example, it denotes visibility property with an icon of eye; and when the button is pressed, the eye icon turns into closed-eye icon.

Inside the paint() method, this is my current code to create the button:

QStyleOptionButton buttonVis;
buttonVis.rect = getButtonVisibilityRect();
buttonVis.iconSize = QSize(sizeX, sizeY);
buttonVis.icon = icon;
buttonVis.state = QStyle::State_Enabled;
buttonVis.features = QStyleOptionButton::None;

QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonVis, painter);

The icon that I load to the buttonVis is created by:

QIcon icon;
icon.addPixmap(QPixmap(":/control-visibility.svg"), QIcon::Normal, QIcon::On);
icon.addPixmap(QPixmap(":/control-visibilityNo.svg"), QIcon::Normal, QIcon::Off);

For the moment when I run my program, the button has an icon with closed eye. Is there a command to control which icon is displayed? If my initial layout is not possible to implement, what is the right direction to go?

EDIT: I found out how to select which icon to use in order to simulate the checkbox look. Instead if line buttonVis.state = QStyle::State_Enabled; there should be:

if (/* current item checkbox checked? */)
    buttonVis.state = QStyle::State_Enabled | QStyle::State_On;
else
    buttonVis.state = QStyle::State_Enabled | QStyle::State_Off;

The problem now is to figure out what is that condition or how to set it up from the editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index). The problem is that I cannot really change option by myself since it is constant reference. Any ideas how to do it, or how to get around it?


Solution

  • Finally, I figured out how to set up certain flag and then test for it and see if the button changed an icon.

    So, for the icon change, as I mentioned on the edit of my question, I have to use something like:

    buttonVis.state |= QStyle::State_Enabled;
    buttonVis.state |= isChanged? QStyle::State_Off : QStyle::State_On;
    

    So it comes down on how to set up isChanged flag. And it can be done within editorEvent() method of the delegate:

    bool Delegate::editorEvent(QEvent *event, QAbstractItemModel *model, const StyleOptionViewItem &option, const QModelIndex &index)
    {
        if (/* event is release and it is over the button area*/)
        {
            bool value = index.data(Qt::UserRole).toBool();
            // this is how we setup the condition flag
            model->setData(index, !value, Qt::UserRole);
            return true;
        }
    }
    

    Now to use the setup flag, we do it in the paint() event right before we set up buttonVis.state:

    bool isChanged = index.data(Qt::UserRole).toBool();
    

    By adding these steps my QStyleOptionButton is now behaving like a checkbox, but it changes icons as states.