c++ - 带动画的 QStateMachine 事件循环

标签 c++ qt

我想用 QStateMachine 创建一个无限循环,其中我还需要动画。

QColor leastTransparent, mostTransparent = color();
leastTransparent.setAlpha(250);
mostTransparent.setAlpha(150);

QState *s1 = new QState();
s1->assignProperty(this, "color", leastTransparent);

QState *s2 = new QState();
s2->assignProperty(this, "color", mostTransparent);

QSignalTransition *transition =  s1->addTransition( this, SIGNAL(triggerSignal()),s2);
QSignalTransition *transition2 = s2->addTransition(s2, SIGNAL(entered),s1);

QPropertyAnimation* animation = new QPropertyAnimation( this, "color");
animation->setDuration( 5000 );
transition->addAnimation(animation);

QPropertyAnimation* animation2 = new QPropertyAnimation( this, "color");
animation2->setDuration(10000);
transition2->addAnimation(animation2);

m_stateMachineAnimation->addState(s1);
m_stateMachineAnimation->addState(s2);
m_stateMachineAnimation->setInitialState(s1);
m_stateMachineAnimation->setGlobalRestorePolicy(QStateMachine::RestoreProperties);
m_stateMachineAnimation->start();

我在这里期望的是在“triggerSignal”之后的前 5 秒颜色会变得更加不透明。状态将是“s2”。并且比“s2”的输入信号被触发,它会在 10 秒内变得越来越透明。

但是我让 s2 立即触发,而不是在“triggerSignal”之后立即等待 5 秒,而不是立即再次触发 s1,而无需等待 10 秒。

为什么 QStateMachine 没有考虑我的持续时间。我怎样才能用QStateMachine实现这样的动画

最佳答案

您似乎希望动画创建某种中间状态。它没有这样的事情。过渡只是触发动画。您立即从 s2 过渡到 s1,没有时间让动画完成。相反,您需要在设置属性的最终值时显式触发后续转换。 QState::propertiesAssigned 信号对于这个目的是最有用的。或者,您可以使用动画的 finished() 信号。

在下面的示例中,在窗口内单击以启动动画循环:

// https://github.com/KubaO/stackoverflown/tree/master/questions/statemachine-animation-42682462
#include <QtWidgets>

const char kColor[] = "color";
class Widget : public QWidget {
   Q_OBJECT
   Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
   QColor m_color{Qt::blue};
   QStateMachine m_machine{this};
   QState s0{&m_machine}, s1{&m_machine}, s2{&m_machine};
   QEventTransition t01{this, QEvent::MouseButtonPress};
   QPropertyAnimation anim_s1{this, kColor}, anim_s2{this, kColor};
   void paintEvent(QPaintEvent *) override {
      QPainter{this}.fillRect(rect(), m_color);
   }
   Q_SIGNAL void colorChanged(const QColor &);
public:
   Widget() {
      connect(this, &Widget::colorChanged, [this]{ update(); });
      s1.assignProperty(this, kColor, QColor{Qt::red});
      s2.assignProperty(this, kColor, QColor{Qt::green});

      t01.setTargetState(&s1);
      s0.addTransition(&t01);                              t01.addAnimation(&anim_s1);
      s1.addTransition(&s1, &QState::propertiesAssigned, &s2)->addAnimation(&anim_s2);
      s2.addTransition(&s2, &QState::propertiesAssigned, &s1)->addAnimation(&anim_s1);

      anim_s1.setDuration(1000);
      anim_s2.setDuration(2000);

      m_machine.setInitialState(&s0);
      m_machine.start();
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Widget w;
   w.setFixedSize(300, 200);
   w.show();
   return app.exec();
}
#include "main.moc"

顺便说一句,这表明动画插入了 RGB 值,导致颜色在 redblue 之间变暗,因为值从 (1 ,0,0)(.5,.5,0)(0,1,0)。对于人类消费,插值 HSV 更有意义,这样值(亮度)保持不变,只有色调(我们人类真正称之为“颜色”)发生变化。

关于c++ - 带动画的 QStateMachine 事件循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42682462/

相关文章:

c++ - Qt "Creating SSL context"错误在几台电脑上

c++ - 多个函数需要相同的参数(如何优化),

c++ - Qt 应用程序中的 Windows 资源管理器

qt - qmake 中自动复制 DLL 不起作用

C++ 模板访问具有不同类型的函数

c++ - 使用 isalpha 函数时不需要 std 命名空间

c++ - 如何正确传递 zmq 上下文 (void *)?

c++ - 有谁知道如何使用 qt creator 调试子进程?

c++ - QString 和一些 Qt 类被识别为不完整类型

c++ - Qt:QuaZip 提取文件并在 QProgressDialog 中显示其进度