动画框架

动画框架:Kinetic项目的一部分,主要目的是提供一种简单的方法用于创建动画的和平滑的GUI。通过Qt动画属性,Qt动画框架为部件和其他QObject对象的动画操作提供了非常大的自由性。Qt动画框架也能用于图形视图框架中。

在这片文章中,我们阐述了Qt动画框架的基本结构。我们也提供了一些通用性编码技术方面的例子用于动画操作QObject和图形项。

动画架构

宏观了解下Qt动画框架结构以及其怎么被使用于Qt动画属性。下图展示了Qt动画框架中的一些重要类。

Qt的动画框架由基类QAbstractAnimation及其两个子类QVariantAnimation和QAnimationGroup组成。QAbstractAnimation类是所有动画类的祖先。它包含了一些在框架中被普遍使用的基本功能;尤其是启动、停止和暂停动画功能。它也接收定时触发通知。

Qt动画框架更是提供了QPropertyAnimation类,该类继承于QVariantAnimation类,用于对Qt属性的动画操作(Qt属性系统是Qt元对象系统的一部分)。QPropertyAnimation类使用缓和曲线算法对属性进行插值演化操作。因此当你想动画改变一个值时,你就声明该值为一个属性值并且使该类为成为一个QObject对象。这给我们提供了很大的方便性去动画操作现有的部件和其他的QObject对象。

复杂动画可以通过构建QAbstractAnimation树形结构来构造。该树主要使用QAnimationGroup,QAnimationGroup类是一个包含其他动画类的容器类;同时QAnimationGroup类也是QAbstractAnimation类的子类,因此一个容器可以包含其他容器。

Qt动画框架既是独立的一部分,也是Qt状态机框架的一部分。Qt状态机框架提供一个状态用来行使动画。当QState进入或者退出时可以改变属性,当这个动画状态提供了一个QPropertyAnimatio时,则动画状态即在这些值之间进行插值衍化操作。后续我们将了解的更加仔细。

在幕后,动画被一个全局定时器控制着,该定时器对所有动画对象发送更新命名。

动画框架中的类


动画Qt属性

正如上述所提到的,QPropertyAnimation类能够修改Qt属性值。正是该类用于改变动画属性值;事实上,它的基类QVariantAnimation是一个抽象类,所以QVariantAnimation不能被直接使用。

我们选用Qt动画属性的一个主要原因是由于它给了我们很大的自由性去动画操作已经存在的类,尤其是拥有bounds、colors等属性的QWidget类(QWidget能被嵌入到QGraphicsView类)。我们看看一个小例子:

int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton button("Animated Button");button.show();QPropertyAnimation animation(&button, "pos");animation.setDuration(3000);animation.setStartValue(button.pos());animation.setEndValue(button.pos() + QPoint(100,100));QObject::connect(&button,&QPushButton::clicked,[&]{animation.start();});a.exec();return 0;
}


上述代码即在10秒的期限把button从屏幕的左上角移动到(250,250)点处。

上述代码在开始值与结束值之间做了线性插值。当然,设置的值在开始处与结束处之间的数值也是合理的,那么插值衍化就沿这些点进行。

int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton button("Animated Button");button.show();QPropertyAnimation animation(&button, "pos");animation.setDuration(3000);QPoint pos = button.pos();animation.setKeyValueAt(0, pos);animation.setKeyValueAt(0.8, pos + QPoint(100,100));animation.setKeyValueAt(1, pos);QObject::connect(&button,&QPushButton::clicked,[&]{animation.start();});a.exec();return 0;
}

在这个例子中,在8秒的期限将button移到(250,250),然后在剩下的2秒时间移回至初始的位置;这些点之间的移动都是通过线性插值的。

你也可以动画操作没有申明动画属性的QObject对象中的值,但是唯一的条件是该值有个能进行修改的设置函数。所以你可以进行子类化,在该类中包含声明属性的值并且有个设置函数。每个Qt属性需要一个获取值的访问函数,因此如果类本身没提供对该值的访问函数的话,你自己就需要提供一个。

class MyGraphicsRectItem : public QObject, public QGraphicsRectItem
{Q_OBJECTQ_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
};

如上所示的代码例子中,我们子类化QGraphicsRectItem类并且定义了”geometry”属性。现在我们即可动画操作MyGraphicsRectItem的位置信息了,即使QGraphicsRectItem没有提供”geometry”属性。

动画和图形视图框架

当你想动画操作QGraphicsItem时,你也是使用QPropertyAnimation类。然而,QGraphicsItem并不继承于QObject。一个好的解决办法是子类化一个你需要的图形项,同时子类也继承于QObject。使用这种方法,QPropertyAnimation类就能使用于QGraphicsItem中。下面的代码例子展示了这种解决办法。另一种可行性是只继承于QGraphicsWidget,因为QGraphicsWidget继承于QObject。

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

就如上述所描述的那样,我们定义了一个我们需要动画操作的属性值。

注意:QObject必须是第一个继承者,因为出于元对象系统的要求。

缓和曲线

QPropertyAnimation在开始与结束之间执行插值操作。除了对动画操作设置更多关键值之外,你也可以使用缓和曲线,缓和曲线控制着在0与1之间的插值速度,如果你想在没有改变插值路径的情况下改变动画速度,那么缓和曲线是很有用的。

int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton button("Animated Button");button.show();QPropertyAnimation animation(&button, "pos");animation.setDuration(3000);QPoint pos = button.pos();animation.setKeyValueAt(0, pos);animation.setKeyValueAt(1, pos + QPoint(100,100));
//    animation.setKeyValueAt(1, pos);animation.setEasingCurve(QEasingCurve::OutBounce);QObject::connect(&button,&QPushButton::clicked,[&]{animation.start();});a.exec();return 0;
}


上述代码中,动画即沿着OutBounce曲线,该曲线样式是到结束处会弹跳起来像个弹跳球。QEasingCurve类有大量的供你选择的曲线,它们被定义成QEasingCurve::Type枚举。如果你需要另外的曲线样式,你也可以自己实现一个,然后用QEasingCurve注册它既可。

动画分组

一个应用程序常常包含不止一个动画。例如,你或许希望同时移动不止一个图形项或者一个接着一个的顺序移动它们。

QAnimationGroup (QSequentialAnimationGroup和QParallelAnimationGroup)的子类是动画容器类,因此多个动画可以被串行或者并行。QAnimationGroup类就是一个例子,其不操作动画属性,但是它能周期性的获得定时通知,这使得它能把定时通知应用于动画中,从而进行控制。

下面我们来看看使用QSequentialAnimationGroup和QParallelAnimationGroup的例子:

Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *bonnie = new QPushButton("Bonnie",this);bonnie->show();QPushButton *clyde = new QPushButton("Clyde",this);clyde->show();QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry",this);// Set up anim1anim1->setDuration(10000);anim1->setStartValue(bonnie->rect());anim1->setEndValue(bonnie->rect().adjusted(100,300,100,300));QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry",this);// Set up anim2anim2->setDuration(10000);anim2->setStartValue(clyde->rect());anim2->setEndValue(clyde->rect().adjusted(300,100,300,100));QParallelAnimationGroup *group = new QParallelAnimationGroup(this);group->addAnimation(anim1);group->addAnimation(anim2);group->start();resize(400,400);
}


并行容器内的动画是同时进行的,调用它的start()函数即开始操作它所管理的所有动画。

毫无疑问,QSequentialAnimationGroup按顺序播放其动画。 前一个动画结束后,它将开始列表中的下一个动画。

Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *bonnie = new QPushButton("Bonnie",this);bonnie->show();QPushButton *clyde = new QPushButton("Clyde",this);clyde->show();QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry",this);// Set up anim1anim1->setDuration(10000);anim1->setStartValue(bonnie->rect());anim1->setEndValue(bonnie->rect().adjusted(100,300,100,300));QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry",this);// Set up anim2anim2->setDuration(10000);anim2->setStartValue(clyde->rect());anim2->setEndValue(clyde->rect().adjusted(300,100,300,100));QSequentialAnimationGroup *group = new QSequentialAnimationGroup(this);group->addAnimation(anim1);group->addAnimation(anim2);group->start();resize(400,400);
}


因为动画容器类也是属于动画,所以你可以把加入到其他动画容器里;用这种方法你就可以建造一个动画树结构,该结构指定了动画之间的相互时间关系。

动画和状态

当使用Qt状态机时,我们可以使用QSignalTransition或QEventTransition类将一个或者多个动画与状态之间的切换中进行关联。这些类继承于QAbstractTransition,QAbstractTransition类提供了方便的函数addAnimation(),该函数在状态切换发生的情况下能触发一个或多个被附加的动画。

我们也可以和状态进行属性关联,而不是自己设置开始和结束值,下面就是一段完整的动画操作QPushButton位置的代码例子:

Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *button = new QPushButton("Animated Button",this);button->show();QStateMachine *machine = new QStateMachine(this);QState *state1 = new QState(machine);state1->assignProperty(button, "geometry", QRect(0, 0, 200, 30));machine->setInitialState(state1);QState *state2 = new QState(machine);state2->assignProperty(button, "geometry", QRect(250, 250, 200, 30));QSignalTransition *transition1 = state1->addTransition(button,&QPushButton::clicked, state2);transition1->addAnimation(new QPropertyAnimation(button, "geometry"));QSignalTransition *transition2 = state2->addTransition(button,&QPushButton::clicked, state1);transition2->addAnimation(new QPropertyAnimation(button, "geometry"));machine->start();resize(500,300);
}

Animation Framework相关推荐

  1. Qt动画框架The Animation Framework

    一个网友翻译的,没有翻译完,我把剩下的那部分翻译出来贴出来 动画框架是Kinetic(运动)项目的一部分,它的目标是提供一中简单的方法创建动画的和流畅的GUI.借助Qt动画属性,可以提供非常自由的动画 ...

  2. C++ Qt Animation Framework基操

    Qt Animation Framework ,该框架提供了一些预定义的动画效果,如淡入淡出.旋转.缩放等,并且可以自定义动画效果. 以下是一个简单的演示如何使用 Qt Animation Frame ...

  3. Qt动画框架Animation Framework

    Qt动画框架 Qt动画框架 动画架构 动画框架中的类 动画Qt属性 动画和图形视图框架 缓和曲线 将动画放在一起 Qt动画框架 动画框架旨在为创建动画和平滑的GUI提供一种简便的方法.通过对Qt属性进 ...

  4. Facebook POP 使用指南

    Facebook POP 使用指南 Pop是一个动画引擎,用以扩展iOS.OSX的动画类型.相较于iOS.OSX中的基本动画效果,Pop扩展后支持弹簧动画效果与衰减动画效果,你可以用Pop动画引擎来构 ...

  5. Animated Eye Candy for Programmers

    作者采用vs2008编译,c#代码 Animated Eye Candy for Programmers By Phillip Piper | 17 Apr 2010 A class library ...

  6. QT 定时器与动画实现

    前言 Qt提供图形视图框架(Graphics View Framework).动画框架(The Animation Framework)和状态机框架(The State Machine Framewo ...

  7. 添加three20模板的方法

    Three20是预编译静态库,最简单的方法是使用Xcode的依赖工程特性,下面是方法: 1. 复制(Clone命令)three20 git(GitHub) 目录: `git clone git://g ...

  8. MPEG4 (ISO/IEC 14496) 文档内容 简介

    ISO/IEC 14496是MPEG专家组制定的MPEG-4标准于1998年10月公布第1版,1999年1月成为国际标准,1999年12月公布了第2版,2000年初成为国际标准. 就是说白了就是MPE ...

  9. ffmpeg源码分析及mp4文件解析

    一.mp4文件的组织 1. mp4文件的box(ffmpeg中叫atom) mp4是由一系列的box组成的,每个box的header是8个字节(4字节的长度,4字节的type) 第一个box比较特殊, ...

最新文章

  1. 一篇文章搞懂fof好友推荐案例
  2. c转义字符以及常见问题和解决方法||c中的注释
  3. Developer Tools
  4. php识别名片,用户信息名片怎么利用PHP实现自动生成
  5. mysql8.0.19.0_分享MySql8.0.19 安装采坑记录
  6. 团队作业(五):冲刺总结
  7. sql注入攻击实例mysql_MySQL 处理SQL注入攻击
  8. 魅族16s封胶事件结果:属极个别封胶漏点 双方协商执行一赔二
  9. MySQL : mysql连接报 Communications link failure
  10. 一个小时快速搭建微信小程序教程
  11. tcp连接python_python网络编程--TCP连接的三次握手(三报文握手)与四次挥手
  12. Java架构师成长之道之Java数据存储
  13. YOLOX安装部署使用训练教程以及报错
  14. 多边形面积计算公式, 根据GPS经纬度计算面积
  15. 再说“恢复被删除的文件”(转)
  16. 华为运营商级路由器配置示例 | 配置OptionB方式跨域BGP VPLS示例(ASBR兼做PE)
  17. excel多条件筛选公式
  18. css table自适应斜线
  19. 皕杰报表在chrome中emitter=print无效问题的解决
  20. WifiManager自动连接wifi接入点

热门文章

  1. MySQL01:MySQL概述
  2. 虚拟ip工具_《跟唐老师学习云网络》 - ip命令
  3. python列表到元祖_python列表与元祖
  4. beta分布_常用概率分布总结(2)
  5. 用Typescript 开发 node.js (方法2)
  6. bzoj3456:城市规划
  7. 025Python路--安装第三方模块
  8. Tomcat的部署+第一个Servlet
  9. 卸载驱动出现:rmmod: can't change directory to '/lib/modules': No such file or directory
  10. FreeMarker 日期转换