如何向 QPushButton 添加悬停过渡?

Posted

技术标签:

【中文标题】如何向 QPushButton 添加悬停过渡?【英文标题】:How to add a hover transition to QPushButton? 【发布时间】:2019-04-04 17:10:11 【问题描述】:

我尝试使用样式表制作自定义QPushButton。当我们将鼠标悬停在按钮上时,我想自定义按钮的颜色。它有效,但我想设置一个过渡持续时间。 但在 Qt 中,此选项不可用。

这是我的自定义按钮:

#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; ");

“过渡 0.9s”的说法不起作用。

这是example in CSS。

还有其他方法吗?

【问题讨论】:

QSS 不是 CSS。没有transition 属性。 Here 是所有可用属性的列表。 这个问题已经有两个答案了。我可以请您提供反馈并接受其中之一。 【参考方案1】:

更新

由于某种原因,建议的解决方案在 Windows 10 上无法按预期工作。我已使用 painter.setOpacity(0.25);painter.fillRect(rect(), m_currentColor); 作为解决方法更新了答案。 GitHub 存储库中的代码也已更新。


原因

QSS 不是 CSS。没有过渡属性。 Here 是所有可用属性的列表。

解决方案

我建议您不要使用样式表,而是采用另一条路径,这条路径更长,但给您更大的灵活性。这是解决方案:

    创建QPushButton 的子类,例如AnimatedHoverButton

    通过重新实现QPushButton::event 来获得有关QEvent::HoverEnterQEvent::HoverLeave events 的通知

     bool AnimatedHoverButton::event(QEvent *event)
     
         switch (event->type()) 
             case QEvent::HoverEnter:
                 animateHover(true);
                 break;
             case QEvent::HoverLeave:
                 animateHover(false);
                 break;
             default:
                 break;
         
    
         return QPushButton::event(event);
     
    

    使用QVariantAnimation 创建inout 过渡

     void AnimatedHoverButton::animateHover(bool in)
     
         if (m_transition)
             m_transition->stop();
    
         m_transition = new QVariantAnimation(this);
         m_transition->setDuration(m_duration);
         m_transition->setStartValue(m_currentColor);
         m_transition->setEndValue(in ? palette().highlight().color()
                                      : Qt::transparent);
    
         connect(m_transition, &QVariantAnimation::valueChanged,
                 this, [this](const QVariant &value)
             m_currentColor = value.value<QColor>();
             repaint();
         );
    
         connect(m_transition, &QVariantAnimation::destroyed,
                 this, [this]()
             m_transition = nullptr;
             repaint();
         );
    
         m_transition->start(QAbstractAnimation::DeleteWhenStopped);
     
    

    通过重新实现 QPushButton::paintEvent 事件处理程序并考虑动画的当前值来绘制按钮

     void AnimatedHoverButton::paintEvent(QPaintEvent */*event*/)
     
         QStylePainter painter(this);
         QStyleOptionButton option;
    
         initStyleOption(&option);
    
         option.state &= ~QStyle::State_MouseOver;
    
         painter.drawControl(QStyle::CE_PushButton, option);
         painter.setOpacity(0.25);
         painter.fillRect(rect(), m_currentColor);
     
    

注意:此解决方案使用小部件的调色板来设置动画的开始和结束值。

示例

解决方案可能看起来很复杂,但幸运的是,我为您准备了一个工作示例,说明如何实现和使用 AnimatedHoverButton 类。

以下代码片段使用AnimatedHoverButton 类生成结果,类似于您提供的 CSS 示例:

#include <QApplication>
#include "AnimatedHoverButton.h"

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    AnimatedHoverButton button(QObject::tr("Hover Over Me"));

    button.setTransitionDuration(300);
    button.resize(300, 150);
    button.show();

    return a.exec();

示例的完整代码可在GitHub 获得。

结果

给定的示例产生以下结果:

【讨论】:

【参考方案2】:

您可以使用Animation。

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

#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();

它会与外部 qss 设置冲突。所以设置SetColor中的所有qss。

【讨论】:

以上是关于如何向 QPushButton 添加悬停过渡?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:如何在悬停、div 的 BORDER-RADIUS 和 MARGIN 上添加过渡?

鼠标在圆角QPushButton时如何不触发悬停状态?

如何同时对 QPushButton 应用悬停和格式化?

将鼠标悬停在 Tailwindcss 中时如何增加文本输入宽度(带过渡)

如何为边框动画添加悬停过渡

CSS:我可以为图像颜色更改悬停效果添加轻松过渡吗?