0

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?

vicrucann
  • 1,703
  • 1
  • 24
  • 34

2 Answers2

0

You can try something like this:

QStyleOptionButton option;
option.initFrom(this);
...
QStylePainter p(this);
if (option.state.testFlag(QStyle::State_Sunken)) {
    p.drawPixmap(this->rect(), QPixmap(":/control-visibility"));
} else {
    p.drawPixmap(this->rect(), QPixmap(":/control-visibilityNo"));
}

Be careful with SVG file, try first with PNG.

QStyle::State_Sunken 0x00000004 Used to indicate if the widget is sunken or pressed.

MBach
  • 1,647
  • 16
  • 30
  • thanks for the reply. I found how to switch the icons: `buttonVis.state = QStyle::State_Enabled | QStyle::State_Off;` or `buttonVis.state = QStyle::State_Enabled | QStyle::State_On;`. I tried your proposed condition `option.state.testFlag(QStyle::State_Sunken)`, but it does not seem to do the trick. It does not seem this flag is set whenever I click on my button, and I am not sure how to force it to switch the states automatically. In delegate's `editorEvent` I can check when I press on the button, however, I cannot change the `option` since it is passed as `const &`. – vicrucann Mar 16 '16 at 00:21
0

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.

vicrucann
  • 1,703
  • 1
  • 24
  • 34