How to add a hover transition to QPushButton?

前端 未结 2 1066
情歌与酒
情歌与酒 2021-01-06 17:31

I try to make a custom QPushButton with a stylesheet. I want to custom color of button when we mouse over it. It works, but I want to put a transition duration.

2条回答
  •  不知归路
    2021-01-06 17:46

    Cause

    QSS is not 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, e.g. AnimatedHoverButton

    2. Get notified about QEvent::HoverEnter and QEvent::HoverLeave events by reimplementing QPushButton::event

      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

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

      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.

    The following code fragment uses the AnimatedHoverButton class to produce a result, similar to the CSS example you have provided:

    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.

    Result

    The given example produces the following result:

提交回复
热议问题