赞
踩
动画框架的目的是提供一种简单的方法来创建平滑的、具有动画效果的GUI界面。
该框架是通过控制Qt的属性来实现动画的,它可以应用在窗口部件和其他QObject对象上,也可以应用在图形视图框架中。
动画框架在Qt 4.6中被引入。该部分内容可以在帮助中通过TheAnimationFramework
关键字查看。
动画框架中主要的类及其关系如图11-6所示。
基类QAbstractAnimation
和它的两个子类QVariantAnimation
以及QAnimationGroup
构成了动画框架的基础。
这里的QAbstractAnimation
是所有动画类的祖先,它定义了一些所有动画类都共享的功能函数,比如动画的开始、停止和暂停等;它也可以接收时间变化的通知,通过继承这个类可以创建自定义的动画类。
动画框架中提供了QPropertyAnimation
类,继承自QVariantAnimation
, 用来执行Qt属性的动画。
这个类使用缓和曲线(easing curve)
来对属性进行插值。
如果要对一个值使用动画,则可以创建继承自QObject 的类,然后在类中将该值定义为一个属性。
属性动画
为现有的窗口部件以及其他QObject子类提供了非常灵活的动画控制。
Qt现在支持的可以进行插值的QVariant类型
有: Int、Uint、Double、Float、QLine、QLineF .QPoint, QPointF 、QSize、QSizeF、QRect、QRectF和QColor等。
如果要实现复杂的动画,则可以通过动画组QAnimationGroup
类实现,它的功能是 作为其他动画类的容器,一个动画组中还可以包含另外的动画组。
-动画框架也被设计作为状态机框架的一部分,将两者结合使用可以实现更为强大的功能。
前面已经讲到QPropertyAnimation
类可以对Qt属性进行插值,如果一个值要实现动画效果,则就要使用这个类,而它的父类QVariantAnimation
是一个抽象类
,无法直接使用。
之所以要使用Qt属性来进行动画的最主要原因 是这样可以为已经存在的Qt API中的类提供灵活的动画设置。
可以在QWidget类的帮助文档中查看它所有的属性,当然,并不是所有的属性都可以设置动画, 必须是前面讲到的Qt支持的QVariant类型
。
下面来看一个例子:
新建空的Qt项目Empty qmake Project,名称为myanimation,完成后先在项目文件中添加“QT十= widgets"- -行代码并保存该文件,然后添加新文件main.cpp,并在其中添加如下代码:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> int main(int argc, char* argv[ ]) { QApplication app(argc, argv); QPushButton button("Animated Button"); button.show(); QPropertyAnimation animation(&button, "geometry"); animation.setDuration(10000); animation.setStartValue(QRect(0, 0, 120, 30)); animation.setEndValue(QRect(250, 250, 200, 60)); animation.start(); return app.exec(); }
这里创建了一个按钮部件button并让其显示,然后为按钮部件的geometry属性
创建了动画,并使用setDuration()
函数 指定了动画的持续时间为10000毫秒(即10秒)
然后使用函数setStartValue( )
和setEndValue()
分别设置了动画开始和结束时geometry 属性的值
最后调用start()函数开始动画
。
这样就实现了按钮部件在10秒内从屏幕的(0, 0)点移动到(250,250)点,与此同时由宽120、高30的大小变为宽200、高60的大小的动画。
除了设置属性开始和结東的值以外,还可以调用setKeyValueAt(qreal step, const QVariant & value)
函数在 动画中间为属性设置值。
其中:
将程序中调用setStartValue( )和setEndValue( )两个函数的代码更改为:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> int main(int argc, char* argv[ ]) { QApplication app(argc, argv); QPushButton button("Animated Button"); button.show(); QPropertyAnimation animation(&button, "geometry"); animation.setDuration(10000); // animation.setStartValue(QRect(0, 0, 120, 30)); // animation.setEndValue(QRect(250, 250, 200, 60)); animation.setKeyValueAt(0, QRect(0, 0, 120, 30)); animation.setKeyValueAt(0.8, QRect(250, 250, 200, 60)); animation.setKeyValueAt(1, QRect(0, 0, 120, 30)); animation.start(); return app.exec(); }
总共10秒,0.8等于80%,等于8秒
这样就实现了在8秒内按钮部件由(0,0)点移动到(250,250)点,并变化大小,然后在后2秒内又回到原点并且恢复原来大小的动画。
现在可以运行程序查看效果:
在前面程序的运行效果中可以看到,按钮部件的运动过程都是线性的,即匀速运动。除了在动画中添加更多的关键点,还可以使用缓和曲线, 缓和曲线描述了怎样来控制0和1之间的插值速度的功能,这样就可以在不改变插值的情况下来控制动画的速度。
将前面程序中间部分设置值的代码更改如下:
animation.setDuration(2000);
animation.setStartValue(QRect(250, 0, 120, 30));
animation.setEndValue(QRect(250, 300, 120, 30));
animation.setEasingCurve(QEasingCurve::OutBounce);
这里使用了QEasingCurve::OutBounce缓和曲线
,此时运行程序会发现
…
它会使按钮部件就像从开始位置掉落到结束位置的皮球一样出现弹跳效果。
QEasingCurve
类中提供了四十多种缓和曲线,而且还可以自定义缓和曲线
详细可以查看一下
QEasingCurve类
的帮助文档。Qt中还提供了一个Easing Curves Example 的示例程序,可以演示所有缓和曲线的效果。
在一个应用中经常会包含多个动画,例如,要同时移动多个图形项或者让它们一个接一个地串行移动。
使用QAnimationGroup
类可以实现复杂的动画,它的两个子类QSequentialAnimationGroup
和QParallelAnimationGroup
分别提供了串行动画组
和并行动画组
。
下面先来看一个串行动画组
的例子。
在前面程序的main. cpp文件中添加头文件# include < QSequentialAnimationGroup>,再将主函数的中间部分内容更改如下:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> #include <QSequentialAnimationGroup> int main(int argc, char* argv[ ]) { QApplication app(argc, argv); QPushButton button("Animated Button"); button.show(); // 按钮部件的动画1 QPropertyAnimation *animation1 = new QPropertyAnimation(&button, "geometry"); animation1->setDuration(2000); animation1->setStartValue(QRect(250, 0, 120, 30)); animation1->setEndValue(QRect(250, 300, 120, 30)); animation1->setEasingCurve(QEasingCurve::OutBounce); // 按钮部件的动画2 QPropertyAnimation *animation2 = new QPropertyAnimation(&button, "geometry"); animation2->setDuration(1000); animation2->setStartValue(QRect(250, 300, 120, 30)); animation2->setEndValue(QRect(250, 300, 200, 60)); // 串行动画组 QSequentialAnimationGroup group; group.addAnimation(animation1); group.addAnimation(animation2); group.start(); return app.exec(); }
这是串行动画组,此时运行程序就会先执行动画1,执行完成之后才执行动画2,动画的执行顺序与加入动画组的顺序是一致的。
动画1是2s内曲线运动从250,0到250,300,等于下落,但是是曲线(曲速)
动画2是1s内变大小,从120,30高宽变为200,60 等于高宽都增大了,1s内变大
下面再看一个并行动画组的例子:
先添加头文件# include < QParallelAnimationGroup> ,再将主函数的中间部分内容更改如下:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> #include <QSequentialAnimationGroup> #include <QParallelAnimationGroup> int main(int argc, char* argv[ ]) { QApplication app(argc, argv); QPushButton button1("Animated Button"); button1.show(); QPushButton button2("Animated Button2"); button2.show(); // 按钮部件1的动画 QPropertyAnimation *animation1 = new QPropertyAnimation(&button1, "geometry"); animation1->setDuration(2000); animation1->setStartValue(QRect(250, 0, 120, 30)); animation1->setEndValue(QRect(250, 300, 120, 30)); animation1->setEasingCurve(QEasingCurve::OutBounce); // 按钮部件2的动画 QPropertyAnimation *animation2 = new QPropertyAnimation(&button2, "geometry"); animation2->setDuration(2000); animation2->setStartValue(QRect(400, 300, 120, 30)); animation2->setEndValue(QRect(400, 300, 200, 60)); // 并行动画组 QParallelAnimationGroup group; group.addAnimation(animation1); group.addAnimation(animation2); group.start(); return app.exec(); }
现在运行程序可以看到,两个按钮部件的动画是同时进行
的。
另外,使用动画组还有一个好处,就是可以将它看作一个独立的动画,从而进行暂停、停止或者添加到其他动画组等操作。
要对QGraphicsItem
使用动画,也可以使用QPropertyAnimation
类。
但是, QGraphicsItem
并不是继承自QObject
类,所以直接继承自QGraphicsItem
的图形项并不能直接使用QPropertyAnimation
类来创建动画。
Qt 4.6中提供了一个QGraphicsItem
的子类QGraphicsObject
,它继承自QObject和QGraphicsItem
,这个类为所有需要使用信号﹑槽以及属性的图形项提供了一个基类,通过创建这个QGraphicsObject类的子类就可以使用属性动画了。
QGraphicsObject
还提供了多个常用的属性,比如位置pos ,透明度opacity ,旋转rotation和缩放scale等,这些都可以直接用来设置动画。
下面看个例子:
新建空的Qt项目,名称设置为myitemanimation。完成后先在项目文件中添加“QT+= widgets”一行代码并保存该文件,然后添加新的C++类,类名MyItem,基类设置为QGraphicsObject。完成后更改 myitem.h文件内容如下:
#ifndef MYITEM_H
#define MYITEM_H
#include <QGraphicsObject>
class MyItem : public QGraphicsObject
{
public:
MyItem(QGraphicsItem *parent = 0);
QRectF boundingRect() const;
void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget);
};
#endif // MYITEM_H
创建了一个MyItem 是QGraphicsItem 的子类,定义了二个函数
然后到myitem.cpp文件中,更改内容如下:
#include "myitem.h" #include <QPainter> MyItem::MyItem(QGraphicsItem *parent) : QGraphicsObject(parent) { } QRectF MyItem::boundingRect() const { return QRectF(-10 - 0.5, -10 - 0.5, 20 + 1, 20 + 1); } void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->drawRect(-10, -10, 20, 20); }
最后到main.cpp文件中,更改内容如下:
#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include "myitem.h" #include <QPropertyAnimation> int main(int argc, char* argv[ ]) { QApplication app(argc, argv); QGraphicsScene scene; scene.setSceneRect(-200, -150, 400, 300); MyItem *item = new MyItem; scene.addItem(item); QGraphicsView view; view.setScene(&scene); view.show(); // 为图形项的rotation属性创建动画 QPropertyAnimation *animation = new QPropertyAnimation(item, "rotation"); animation->setDuration(2000); animation->setStartValue(0); animation->setEndValue(360); animation->start(QAbstractAnimation::DeleteWhenStopped); return app.exec(); }
这样就可以在图形视图框架中使用动画了
这里是2s,开始0.结束旋转360。
现在运行程序,图形项已经可以自动旋转了。
当然,这个动画效果也可以使用前面讲到的其他知识来实现,
不过可以看到,使用动画框架是非常简单的,而且如果要实现更加复杂的动画,
那么动画框架的优势就显而易见了。
在使用动画对象时,如果是创建对象的指针,而且执行—遍以后就不再使用,那么可以在 start ()函数中指定DeletcWhenStopped 删除策略
,这样当动画执行结束后便会自动销毁该动画对象。
除了继承QGraphicsObject类以外,当然也可以同时继承Object和 QGraphicsItem类来实现自己的图形项。
注意,QObejct必须是第一个继承的类,这是元对象系统的要求。
另外,还可以继承自QGraphics Widget
类,这个类已经是QObject
的子类了。
如果要使用一个自定义的属性,那么就要先声明该属性,这个可以查看第7章的相关内容。
Qt还提供了一个Animated Tiles Example的示例程序,可以参考一下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。