简体   繁体   English

如何将悬停过渡添加到QPushButton?

[英]How to add a hover transition to QPushButton?

I try to make a custom QPushButton with a stylesheet. 我尝试使用样式表制作自定义QPushButton I want to custom color of button when we mouse over it. 当我们将鼠标悬停在按钮上时,我想自定义按钮的颜色。 It works, but I want to put a transition duration. 它有效,但是我想设置一个过渡持续时间。 But in Qt this option is not available. 但是在Qt中此选项不可用。

Here is my custom button: 这是我的自定义按钮:

#include "bouton.h"

Bouton::Bouton(QString title, QWidget *parent) : QPushButton()
{
  setGeometry(50,50,120,40);
  setText(title);
  setMinimumHeight(30);
  setParent(parent);
  setStyleSheet(" QPushButton {"
              "border-radius: 5px; "
              "border: 1.5px solid rgb(91,231,255); "
              "background-color: white; }"
              "QPushButton:pressed {"
              "border: 1.4px solid rgb(73,186,205); }"
              "QPushButton:hover {"
              "font-size: 16px;"
              "transition: 0.9s; }");
}

The argument "transition 0.9s" doesn't work. 参数“过渡0.9s”无效。

Here is an example in CSS . 这是CSS中示例

Are there other ways to do this? 还有其他方法吗?

Cause 原因

QSS is not CSS . QSS不是CSS There is no transition property. 没有过渡属性。 Here is a list of all available properties. 是所有可用属性的列表。

Solution

Instead of using stylesheets, I would suggest you to take another path, which is longer, but gives you more flexibility. 建议您不要使用样式表,而是采取另一种方法,该方法虽然更长,但是却具有更大的灵活性。 Here is the solution: 解决方法如下:

  1. Create a subclass of QPushButton , eg AnimatedHoverButton 创建QPushButton的子类,例如AnimatedHoverButton

  2. Get notified about QEvent::HoverEnter and QEvent::HoverLeave events by reimplementing QPushButton::event 通过重新实现QPushButton::event获得有关QEvent::HoverEnterQEvent::HoverLeave 事件的通知

     bool AnimatedHoverButton::event(QEvent *event) { switch (event->type()) { case QEvent::HoverEnter: animateHover(true); break; case QEvent::HoverLeave: animateHover(false); break; } return QPushButton::event(event); } 
  3. Create the in and out transition by using QVariantAnimation 创建inout利用过渡QVariantAnimation

     void AnimatedHoverButton::animateHover(bool in) { const QColor &baseColor(palette().brush(QPalette::Button).color()); const QColor &highlightColor(palette().brush(QPalette::Highlight).color()); QColor startValue(in ? baseColor : highlightColor); if (m_transition) { startValue = m_transition->currentValue().value<QColor>(); m_transition->stop(); } m_transition = new QVariantAnimation(this); m_transition->setStartValue(startValue); m_transition->setEndValue(in ? highlightColor : baseColor); m_transition->setDuration(m_duration); connect(m_transition, &QVariantAnimation::valueChanged, [this](const QVariant &value){ m_currentColor = value.value<QColor>(); repaint(); }); connect(m_transition, &QVariantAnimation::destroyed, [this](){ m_transition = nullptr; }); m_transition->start(QAbstractAnimation::DeleteWhenStopped); } 
  4. Paint the button by reimplementing the QPushButton::paintEvent event handler and taking into account the current value of the animation 通过重新实现QPushButton::paintEvent事件处理程序并考虑动画的当前值来绘制按钮

     void AnimatedHoverButton::paintEvent(QPaintEvent * /*event*/) { QStylePainter painter(this); QStyleOptionButton option; QPalette p(palette()); initStyleOption(&option); p.setBrush(QPalette::Button, m_currentColor); option.palette = p; option.state |= QStyle::State_MouseOver; painter.drawControl(QStyle::CE_PushButton, option); } 

Note: This solution uses the widget's palette to set the start and end values of the animation. 注意:此解决方案使用小部件的调色板来设置动画的开始和结束值。

Example

The solution might seem complicated, but fortunatelly I have prepared a working example for you of how to implement and use the AnimatedHoverButton class. 解决方案似乎很复杂,但是幸运的是,我为您准备了一个有效的示例,说明如何实现和使用AnimatedHoverButton类。

The following code fragment uses the AnimatedHoverButton class to produce a result, similar to the CSS example you have provided: 以下代码片段使用AnimatedHoverButton类产生结果,类似于您提供的CSS示例:

auto *button = new AnimatedHoverButton(tr("Hover Over Me"), this);

QPalette p(button->palette());

p.setBrush(QPalette::Button, QColor("#F89778"));
p.setBrush(QPalette::ButtonText, QColor("#FFFFFF"));
p.setBrush(QPalette::Highlight, QColor("#F4511E"));

button->setPalette(p);
button->setTransitionDuration(300);

setCentralWidget(button);
setContentsMargins(10, 10, 10, 10);

The full code of the example is available on GitHub . 该示例的完整代码可在GitHub找到

Result 结果

The given example produces the following result: 给定的示例产生以下结果:

具有突出显示的自定义按钮的窗口

You can use Animation . 您可以使用Animation

MyButton.h MyButton.h

#include <QPushButton>
#include <QColor>
#include <QPropertyAnimation>

class MyButton : public QPushButton
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ GetColor WRITE SetColor)

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

    void SetColor(const QColor& color);
    const QColor& GetColor() const;

protected:
    bool eventFilter(QObject *obj, QEvent *e);

private:
    QColor m_currentColor;

    QPropertyAnimation m_colorAnimation;

    void StartHoverEnterAnimation();
    void StartHoverLeaveAnimation();
};

MyButton.cpp MyButton.cpp

#include "MyButton.h"

#include <QEvent>
#include <QDebug>

MyButton::MyButton(QWidget *parent) :
    QPushButton(parent),
    m_colorAnimation(this, "color")
{
    this->installEventFilter(this);
}

void MyButton::SetColor(const QColor& color)
{
    m_currentColor = color;
    QString css = "QPushButton { border-radius: 5px; ";
    css.append("border: 1.5px solid rgb(91,231,255); ");
    QString strColor = QString("rgb(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue());
    css.append("background-color: " + strColor + "; }");
    setStyleSheet(css);
}

const QColor& MyButton::GetColor() const
{
    return m_currentColor;
}

bool MyButton::eventFilter(QObject *obj, QEvent *e)
{
    if (e->type() == QEvent::HoverEnter) {
        StartHoverEnterAnimation();
    }

    if (e->type() == QEvent::HoverLeave) {
        StartHoverLeaveAnimation();
    }

    return false;
}

void MyButton::StartHoverEnterAnimation()
{
    m_colorAnimation.stop();

    m_colorAnimation.setDuration(900); //set your transition
    m_colorAnimation.setStartValue(GetColor()); //starts from current color
    m_colorAnimation.setEndValue(QColor(100, 100, 100));//set your hover color

    m_colorAnimation.setEasingCurve(QEasingCurve::Linear);//animation style

    m_colorAnimation.start();
}

void MyButton::StartHoverLeaveAnimation()
{
    m_colorAnimation.stop();

    m_colorAnimation.setDuration(900); //set your transition
    m_colorAnimation.setStartValue(GetColor()); //starts from current color
    m_colorAnimation.setEndValue(QColor(255, 0, 0));//set your regular color

    m_colorAnimation.setEasingCurve(QEasingCurve::Linear);//animation style

    m_colorAnimation.start();
}

It will conflict with external qss setting. 它将与外部qss设置冲突。 So set all qss in SetColor . 因此,在SetColor设置所有qss。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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