Change the background color of a QPushButton with QPropertyAnimation

1.5k Views Asked by At

I'm trying to apply a soft color change to a QPushButton clicked event. My first approach with QPropertyAnimation works like a charm.

header:

class myAnim : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor)

public:
    explicit myAnim(QWidget *parent = 0);

    void setColor (QColor color){
        setStyleSheet(QString(" QPushButton { background-color: rgb(%1, %2, %3); }").arg(color.red()).arg(color.green()).arg(color.blue()));
    }

and source:

QPropertyAnimation *anim = new QPropertyAnimation(this, "color");
anim->setDuration(300);                      // duration in ms
anim->setStartValue(QColor(0, 0, 0);
anim->setEndValue(QColor(249, 249, 249));
anim->start();

But since my Button does have a lineargradient as a background I need more than one color to be changed. Tried it with changing the header like so:

void setColor (QColor color[3]){
        setStyleSheet(QString("QPushButton { background: qlineargradient(x1:0, y1:0, x2:0, y2:1,") +
                      QString("stop: 0    rgba(%1, %2, %3, 255),").arg( color[0].red() ).arg( color[0].green() ).arg( color[0].blue() ) +
                      QString("stop: 0.5  rgba(%1, %2, %3, 255),").arg( color[1].red() ).arg( color[1].green() ).arg( color[1].blue() ) +
                      QString("stop: 0.6  rgba(%1, %2, %3, 255),").arg( color[2].red() ).arg( color[2].green() ).arg( color[2].blue() ) +
                      QString("stop: 1    rgba(%1, %2, %3, 255),").arg( color[0].red() ).arg( color[0].green() ).arg( color[0].blue() ));
    }

My question: How do I edit the "setStartValue" and "setEndValue" in the source file correctly??

EDIT 1: The buttons in my app look like this: button_1

Stylesheet of the QPushButton:

background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #f9f9f9 , stop: 0.5 #B5B5B5 , stop: 0.6 #D6D6D6 , stop:1 #f9f9f9 );

Stylesheet for the pressed event:

background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #005da8, stop: 0.5 #2882cc, stop: 0.6 #418ecd, stop:1 #005da8);

After clicking the silver'ish gradient turns into a blue gradient. After releasing they should fade softly into the silver'ish look again. As previously said the first approach does exactly that but with only one flat color. I've never worked with QPainter or a custom paintEvent before so any help would be highly appreciated!

Thanks!

Micha

1

There are 1 best solutions below

1
On

The simplest way to do so would be to define a property for each stop:

Q_PROPERTY(QColor color1 READ color1 WRITE setColor1)
Q_PROPERTY(QColor color2 READ color2 WRITE setColor2)
Q_PROPERTY(QColor color3 READ color3 WRITE setColor3)
Q_PROPERTY(QColor color4 READ color4 WRITE setColor4)

It's pretty ugly though.

In your comment, you mentioned that the RGB component of each colour is the same, and the components were basically 249, 181, 214 and 249. If you know that each colour is based off 249, you could do something like this:

void setColor (QColor color){
    const int base = color.red();
    const int stop2 = (181.0 / 249.0) * base;
    const int stop3 = (214.0 / 249.0) * base;
    setStyleSheet(QString("QPushButton { background: qlineargradient(x1:0, y1:0, x2:0, y2:1,") +
                  QString("stop: 0    rgba(%1, %2, %3, 255),").arg( base ).arg( base ).arg( base ) +
                  QString("stop: 0.5  rgba(%1, %2, %3, 255),").arg( stop2 ).arg( stop2 ).arg( stop2 ) +
                  QString("stop: 0.6  rgba(%1, %2, %3, 255),").arg( stop3 ).arg( stop3 ).arg( stop3 ) +
                  QString("stop: 1    rgba(%1, %2, %3, 255),").arg( base ).arg( base ).arg( base ));
}

This allows you to use any colour for the color property (so long as all components are the same), and the other colours will scale automatically.

As mentioned by @SaZ, modifying stylesheets in this manner can be slow. You could consider using QPalette instead, or (probably the fastest option), override paintEvent() and paint the widget yourself.