简体   繁体   中英

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.

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!

After reading this article and encountering similar issues. This is my work around in c++ not using style sheet from designer.

1>I create Icons one for being pressed and one for normal. In your case we would address it as the hover condition.

2>Add the icons to the resource file.

3>Use the following code for reference...

Where Add_PB is a QPushButton.

Add_PB->setStyleSheet( "*{border-image: url(:/icons/maximize.bmp);}"  
":pressed{ border-image: url(:/icons/maximize_pressed.bmp);}"); 

The key take away here is you can use setStyleSheet to set diffrent icons for different conditons. I couldnt get the above code to work until I used the * operator or "Universal Selector" in the CSS string.

Reference: http://doc.qt.io/qt-5/stylesheet-syntax.html

I maked it in designer, from ui_...h file:

QIcon icon;
icon.addFile(QStringLiteral(":/unpressed.png"), QSize(), QIcon::Normal, QIcon::Off);
icon.addFile(QStringLiteral(":/pressed.png"), QSize(), QIcon::Normal, QIcon::On);
pushButton->setIcon(icon);

In c++ , we can achieve it using the following code:

ui->button->setStyleSheet("QPushButton{border-image : url(./default_Img.png);} QPushButton:hover{border-image : url(./hover_Img.png); }"
                               "QPushButton:focus{border-image : url(./focus_Img.png);}");

I know this is an old question, but I think it may still be useful.

To get a button with only an image showing by default, then a different image on hover, I tried having an icon set in the editor and playing around with the onSelected , onActive , etc. but naturally, it didn't work.

What did work is inspired from @JosephFarrish and from @goerge so credit goes firstly to them. I decided to post my answer as a 'tangible' solution.

For the particular push button, I have 2 images:

  • one shown by default

在此处输入图片说明

  • and on for a hover effect

在此处输入图片说明

My solution for a specific QPushButton is:

QPushButton {
    border-image: url(:/icons/ic-explore);
    background-repeat: no-repeat;
    width: 32px;
    height: 32px;
}

QPushButton:hover {
    border-image: url(:/icons/ic-explore-hover);
    background-repeat: no-repeat;
}

as you can see, the ic-explore and ic-explore-hover are added to my resource file as shown below:

在此处输入图片说明

where the actual icons are in the root project folder, in a folder named icons. The prefix for the icons is given by :/icons/ and this coincidentally happens to be the same name as the icons folder name.

Note with the CSS that I set the width and height of the QPushButton.

I think it's worth mentioning that as of the time of posting this answer, the bug mentioned in the approved answer appears to have been fixed. I have the following stylesheet macro for my buttons. This makes the button icons change correctly when they are hovered over and pressed.

#define BUTTON_STYLESHEET_TEMPLATE(not_pressed, hovered, pressed) "QPushButton {"\
"border-image: url(:icons/" not_pressed ");"\
"background-repeat: no-repeat;"\
"width: 65px;"\
"height: 56px;"\
"}"\
"QPushButton:hover {"\
"border-image: url(:icons/" hovered ");"\
"}"\
"QPushButton:pressed {"\
"border-image: url(:icons/" pressed ");"\
"}"

I applied this to each of my QPushButtons with the setStyleSheet function, passing the three different images for each state into the macro.

button.setStyleSheet(BUTTON_STYLESHEET_TEMPLATE("not_pressed.png", "hovered.png", "pressed.png"));

Hopefully this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM