QPushButton not respecting QIcon mode changes

1.1k Views Asked by At

When applying a QIcon with QPushButton::setIcon(), it appears that mode changes don't respect the mode changes set for the QIcon

QIcon helpIcon;
helpIcon.addPixmap(QPixmap(":/icons/style/help.png"), QIcon::Normal);
helpIcon.addPixmap(QPixmap(":/icons/style/help_hover.png"), QIcon::Active); //ignored?

QPushButton *myButton = new QPushButton(this);
myButton->setIcon(helpIcon);

What I would expect to happen is the icon should change from one pixmap to the other when the button is hovered. Instead, the icon stays the same. It only changes when the button is pressed. I've tried every combination of QIcon::State and QIcon::Mode with no change.

Running Qt 5.12.1

2

There are 2 best solutions below

0
mrg95 On BEST ANSWER

I resolved this by subclassing QPushButton and listening for the enter and leave events. This class switches between base and hover icons. This is more useful for me vs stylesheets because I resize the icons based on the user's DPI.

class CustomButton : public QPushButton
{
    Q_OBJECT
public:
    CustomButton(QWidget *parent = nullptr);

    void setBaseIcon(QIcon icon){
        baseIcon = icon;
        setIcon(baseIcon);
    }

    void setHoverIcon(QIcon icon){hoverIcon = icon;}

private:
    QIcon baseIcon;
    QIcon hoverIcon;

protected:
    virtual void enterEvent(QEvent *){
        setIcon(hoverIcon);
        update();
    }

    virtual void leaveEvent(QEvent *){
        setIcon(baseIcon);
        update();
    }
};
0
Maxim Paperno On

This is simply how QPushButton handles states (and hence icon mode/state), which is different from QToolButton. More specifically it is how the current QStyle subclass uses the button state information to paint the icon. For example, here is the QPushButton::paintEvent() code (follow that to see initStyleOption() call where state data is initialized), then the style options are handed off to the currently active QStyle (which could be eg. WindowsVista/Macintosh/Fusion/StyleSheets depending on OS or settings). Then if we look at, for example, the relevant QFusionStyle code we can see that the icon Active mode is only used when the button has focus. Or same in QCommonStyle (which Windows/WindowsVista/Macintosh styles all fall back to).

To work around this you could use CSS and set an image property for the QPushButton:hover state, or implement your own QProxyStyle::drawControl() method for the CE_PushButtonLabel control element.

CSS: QPushButton:hover { image: url(/path/to/icon.png); }