Search code examples
qtqt-designerqstylesheet

Change QPushButton Icon on hover and pressed


I'm trying to change the Icon of a QpushButton on hover and pressed, I'm using QtDesigner with stylesheets. I tried this

QpushButton{
       qproperty-icon:url(:/images/start.png);
}

QPushButton:hover
{
       qproperty-icon:url(:/images/start_hov.png);
}

But it doesn't work.

I tried setting it from QtDesigner Menu but it didn't work as well.


Solution

  • Unfortunately, it is a bug of Qt which is still not fixed. There's a workaround suggestion within the comments to that bug, basically you could use empty qproperty-icon and reserve the space necessary for it while actually changing background-image property instead:

    QPushButton {
        qproperty-icon: url(" "); /* empty image */
        qproperty-iconSize: 16px 16px; /* space for the background image */
        background-image: url(":/images/start.png");
        background-repeat: no-repeat;
    }
    
    QPushButton:hover {
        background-image: url(":/images/start_hov.png");
        background-repeat: no-repeat;
    }
    

    But the end result looks... not very satisfactory really. You can get much better results if you use C++ to change the button's icon at runtime, here's a simple example using event filter:

    #include <QObject>
    #include <QPushButton>
    #include <QEvent>
    
    class ButtonHoverWatcher : public QObject
    {
        Q_OBJECT
    public:
        explicit ButtonHoverWatcher(QObject * parent = Q_NULLPTR);
        virtual bool eventFilter(QObject * watched, QEvent * event) Q_DECL_OVERRIDE;
    };
    
    ButtonHoverWatcher::ButtonHoverWatcher(QObject * parent) :
        QObject(parent)
    {}
    
    bool ButtonHoverWatcher::eventFilter(QObject * watched, QEvent * event)
    {
        QPushButton * button = qobject_cast<QPushButton*>(watched);
        if (!button) {
            return false;
        }
    
        if (event->type() == QEvent::Enter) {
            // The push button is hovered by mouse
            button->setIcon(QIcon(":/images/start_hov.png"));
            return true;
        }
    
        if (event->type() == QEvent::Leave){
            // The push button is not hovered by mouse
            button->setIcon(QIcon(":/images/start.png"));
            return true;
        }
    
        return false;
    }
    

    Then somewhere in your code setting up the UI you do something like this:

    ButtonHoverWatcher * watcher = new ButtonHoverWatcher(this);
    ui->pushButton->installEventFilter(watcher);
    

    And bingo - you get the button's icon changing on hover and unhover!