主要类关系图
QAbstractAnimation
动画框架基础由基类QAbstractAnimation以及它的两个子类QVariantAnimation,QAnimationGroup组成.QAbstractAnimation是所有动画的祖先.它包含了一些在框架中被普遍使用的基本功能;尤其是启动,停止和暂停动画功能,它也接收定时触发通知.
QPropertyAnimation
Qt动画框架更是提供了QPropertyAnimation类,该类继承自QVariantAnimation,用于对Qt属性的动画操作(Qt属性系统是Qt元对象系统的一部分).QPropertyAnimation类使用缓和曲线算法对属性进行插值演化操作.因此当你想使用动画改变一个值时,需要声明其为一个属性并且使该类继承自QObject.这给我们提供了很大的方便性,去动画操作现有的部件和其它的QObject对象.
QAnimationGroup
复杂动画可以通过构建QAbstractAnimation树形结构来构造.该树主要使用QAnimationGroup.QAnimationGroup类是一个包含其它动画类的容器类;同时QAnimationGroup类也是QAbstractAnimation类的子类,因此一个容器可以包含其它容器.
主要类介绍
名称 | 描述 |
---|---|
QAbstractAnimation | 所有动画类的基类 |
QAnimationGroup | 动画容器的基类 |
QParallelAnimationGroup | 并行动画容器 |
QSequentialAnimationGroup | 串行动画容器 |
QPauseAnimation | QSequentialAnimationGroup 的暂停 |
QVariantAnimation | 动画类的基类 |
QPropertyAnimation | QT属性动画 |
QEasingCurve | 控制动画的缓和曲线类 |
QTimeLine | 控制动画的事件轴类 |
QT属性动画
如上所述,QPropertyAnimation类能够使用插值来修改Qt属性值,正是该类用于改变动画属性值。选择Qt属性动画的主要原因,是因为我们可以很自由的去动画操作QT API中已经存在的类,尤其是拥有bounds、colors等属性的QWidget类(能被嵌入到QGraphicsView中的QWidget).例如:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button,"gemetry");
animation.setDuration(10000);
animation.setStartValue(QRect(0,0,100,30));
animation.setEndValue(QRect(250,250,100,30));
animation.start();
上面的代码 在10秒内把button从左上角(0,0)位置移动到位置(250,250).上面的代码在起始位置和终止位置之间做了线性插值.当然也可以在开始位置和结束位置之间设置其他值,这样插值就会经过这些点.例如:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button,"gemetry");
animation.setDuration(10000);
animation.setKeyValueAt(0.0,QRect(0,0,100,30));
animation.setKeyValueAt(0.8,QRect(250,250,100,30));
animation.setKeyValueAt(1.0,QRect(0,0,100,30));
animation.start();
上面的代码在8秒内把button从(0,0)移动到(250,250),然后在2秒内重新移回到(0,0)位置.这些点之间的移动是通过线性插值完成的.
动画和图形视图框架
我们也可以使用QPropertyAnimation来动画操作QGraphicsItem.然而QGraphicsItem并不继承于QObject,一个好的解决办法是子类化一个你需要的图形项,同时这个类也继承自QObject.通过这种方式,QPropertyAnimation类就能适用于QGraphicsItem.另一种办法是只继承于QGraphicsWidget,因为QGraphicsWidget继承于QObject.例如:
class Pixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
...
注意:因为元对象系统的要求,必须要首先继承子QObject.
缓和曲线
QPropertyAnimation在起始和结束属性值之间进行插值操作.除了为动画添加更多关键值外,也可以使用缓和曲线.化合曲线描述了一种控制在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中有大量的曲线可供选择使用,他们被定义为QEasingCurve::Type枚举.我们也可以自定义缓和曲线,然后用QEasingCurve注册即可.
动画分组
一个程序中经常包含有多个动画,例如你想同时移动多个图形项,或者你想一个接一个的移动他们.QAnimationGroup的子类(QSequentialAnimationGroup 和QParallelAnimationGroup)是其他动画的容器类,这些动画就可以并行或者串行执行.QAnimationGroup类就是一个例子,其不操作动画属性,但是它能周期性的获得定时通知,这使得它能把定时通知应用于它所包含的动画中,从而通过它所包含的动画进行进行控制。
并行动画例子:
QPushButton* bonnie = new QPushButton("Bonnie");
QPushButton* clyde= new QPushButton("clyde");
bonnie->show();
clyde->show();
QPropertyAnimation* anim1 = new QPropertyAnimation(bonnie,"geometry");
QPropertyAnimation* anim2 = new QPropertyAnimation(clyde,"geometry");
QParallelAnimationGroup* group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);
group->start();
串行动画例子:
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);
group.addAnimation(&anim2);
group.start();
因为动画容器类也是动画,所以可以将其加入到其他动画容器中,这样就可以构建出一个动画的树形结构.该树形结构描述了动画彼此之间的运行关系.