动画机制The Animation Framework“一、译”

动画机制

Qt的动画框架提供了一种简单的方式创建GUI动画。通过Qt的属性系统机制,该框架可灵活的使窗口控件和QObject的子类创建动画。同时,该框架也同样适用于Qt的Graphics/View图形视图框架。

本文主要讲解动画框架的基础。通过使QObject的子类、图形单元项动画的基本例子,来演示如何使用。

动画架构

首先我们从高层上看下Qt动画的架构。如下图是动画框架的类图:

image

  • QAbstractAnimation:所有动画对象的基类。它表示框架中所有动画都具有的基本属性,如启动、停止、暂停动画。
  • QPropertyAnimation: 执行Qt属性系统的动画。我们可灵活的对窗口部件、QObject的子类创建属性动画。若想对自己的类成员变量创建动画,首先把它声明成属性Q_PROPERTY,然后类继承QObject。
  • QAnimationGroup:管理多个复杂动画的容器。同时,动画组容器可以嵌套使用。
  • QParallelAnimationGroup:管理动画的容器,多个动画并行运行。
  • QSequentialAnimationGroup:管理动画的容器,多个动画串行运行。

在这背后,动画机制是由一个全局的定时器控制的,但运行时会更新所有的动画对象。

常用类

核心类作用
QAbstractAnimation所有动画的基类
QAnimationGroup管理动画的容器基类
QEasingCurve控制动画的过度曲线
QParallelAnimationGroup平行动画组容器
QSequentialAnimationGroup串行动画组容器
QPauseAnimation管理动画的容器基类
QPropertyAnimation控制动画的过度曲线
QTimeLine控制动画的时间线

Qt属性动画

主要通过QPropertyAnimation完成属性动画,内部会自动插值计算。比如QWidget有边界、位置、大小等属性,可对这些属性简单动画。举个例子,将一个按钮在10s内,从位置(0,0)移动到(250,250):

  QPushButton button("Animated Button");
  button.show();

  QPropertyAnimation animation(&button, "geometry");   //指定要创建动画的目标对象、及属性
  animation.setDuration(10000); //设置动画持续的时间
  animation.setStartValue(QRect(0, 0, 100, 30)); //设置属性geometry的起始大小
  animation.setEndValue(QRect(250, 250, 100, 30)); //设置属性geometry的起始大小

  animation.start();

动画框架内部会根据起点和终点自动线性插值计算,在中间计算出合适的值,然后根据这些算出的若干点运行动画。

再看一个例子,自由的定义若干关键点。将一个按钮在8s内,从位置(0,0)移动到(250,250),然后在2s内,再将位置从(250,250)移动到(0,0):

  QPushButton button("Animated Button");
  button.show();

  QPropertyAnimation animation(&button, "geometry");
  animation.setDuration(10000);

  animation.setKeyValueAt(0, QRect(0, 0, 100, 30)); //设置关键点10 * 0s时的属性值
  animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30)); //设置关键点10 * 0.8s时的属性值
  animation.setKeyValueAt(1, QRect(0, 0, 100, 30)); //设置关键点10 * 1s时的属性值

  animation.start();

更灵活的是,可对自己申明的类创建属性动画。只需要两步:类继承于QObject;声明属性Q_PROPERTY。例子如下:

  class MyGraphicsRectItem : public QObject, public QGraphicsRectItem //继承QObject
  {
      Q_OBJECT
      Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) //声明属性Q_PROPERTY
  };

记住一点:自定义属性需要提供get/set方法。

动画框架与图形视图框架

如果想对图形项QGraphicsItem创建动画,我们可以使用属性动画QPropertyAnimation。但是QGraphicsItem不是继承于QObject,因此就不能直接使用对QGraphicsItem使用属性动画。一种解决方式:对QGraphicsItem创建子类,子类同时继承于QObject、QGraphicsItem。代码如下:

 class Pixmap : public QObject, public QGraphicsPixmapItem
  {
      Q_OBJECT
      Q_PROPERTY(QPointF pos READ pos WRITE setPos)
      ...

需要注意:由于Qt元对象机制,QObject必须是第一个被继承的类。

过度曲线

使用QPropertyAnimation属性动画时,可定义多个关键点。此外也可使用内置的过度曲线QEasingCurve(实际上就是如何对0、1之间的值进行插值计算!)。代码示例如下:

  QPushButton button("Animated Button");
  button.show();

  QPropertyAnimation animation(&button, "geometry");
  animation.setDuration(3000);
  animation.setStartValue(QRect(0, 0, 100, 30));
  animation.setEndValue(QRect(250, 250, 100, 30));

  animation.setEasingCurve(QEasingCurve::OutBounce); //弹跳曲线

  animation.start();

QEasingCurve::Type内置类型很多,具体效果请查看Qt帮助文档。此外,也可以定制过度类型,然后注册到QEasingCurve中。

组合动画

实际中要运行的动画不止一个,好在Qt动画组可以管理并运行多个动画,如下所示:
1. QAnimationGroup:管理多个复杂动画的容器。同时,动画组容器可以嵌套使用。
2. QParallelAnimationGroup:管理动画的容器,多个动画并行运行。
3. QSequentialAnimationGroup:管理动画的容器,多个动画串行运行。

举个并行动画的例子:

 QPushButton *bonnie = new QPushButton("Bonnie");
  bonnie->show();

  QPushButton *clyde = new QPushButton("Clyde");
  clyde->show();

  QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
  // Set up anim1

  QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
  // Set up anim2

  QParallelAnimationGroup *group = new QParallelAnimationGroup;
  group->addAnimation(anim1);   //添加属性动画1
  group->addAnimation(anim2);   //添加属性动画2

  group->start();  //开始执行属性动画组:属性动画1、2并行执行

举个并行串行的例子:

  QPushButton button("Animated Button");
  button.show();

  QPropertyAnimation anim1(&button, "geometry");
  anim1.setDuration(3000);
  anim1.setStartValue(QRect(0, 0, 100, 30));
  anim1.setEndValue(QRect(500, 500, 100, 30));

  QPropertyAnimation anim2(&button, "geometry");
  anim2.setDuration(3000);
  anim2.setStartValue(QRect(500, 500, 100, 30));
  anim2.setEndValue(QRect(1000, 500, 100, 30));

  QSequentialAnimationGroup group;

  group.addAnimation(&anim1); //添加属性动画1
  group.addAnimation(&anim2); //添加属性动画2

  group.start(); //开始执行属性动画组:属性动画1、2串行执行。先执行动画1、在执行动画2。

因QAnimationGroup可嵌套,因此我们能组装成更复杂的动画组。

动画和状态机制

这里先看个简单代码例子,后期在梳理Qt状态机机制时再详细说明。

  QPushButton *button = new QPushButton("Animated Button");
  button->show();

  QStateMachine *machine = new QStateMachine;

  QState *state1 = new QState(machine);
  state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30));
  machine->setInitialState(state1);

  QState *state2 = new QState(machine);
  state2->assignProperty(button, "geometry", QRect(250, 250, 100, 30));

  QSignalTransition *transition1 = state1->addTransition(button,
      SIGNAL(clicked()), state2);
  transition1->addAnimation(new QPropertyAnimation(button, "geometry"));

  QSignalTransition *transition2 = state2->addTransition(button,
      SIGNAL(clicked()), state1);
  transition2->addAnimation(new QPropertyAnimation(button, "geometry"));

  machine->start();

至此,本章主要讲解了Qt框架的使用场景、简单机制及核心类使用。下章结合一个具体的案例练练手。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值