项目背景:主要是想做一个AGV调度仿真软件,第一阶段先完成小车的运动先。所以需要学习一下QT的动画效果,为整个软件打下基础,
动画框架是由基类QAbstractAnimation和它的两个派生类QVariantAnimation、QAnimaitonGroup组成的。动画框架进一步提供了QProPertyAnimation类用于单个控件属性的变化,QAnimationGroup用于多动画的类。这篇文章主要讲解单个动画的实现。
在Qt Creator新建Qt Widgets Application,选择以QWidget为基础类。
接下来的代码在widget.cpp中的Widget函数实现。
QPropertyAnimation
property是属性,animation是动画,所以这个类是专门用于控制控件属性的动画。QPropertyAnimation类继承QVariantAnimation类,能够修改Qt的属性值,如pos、geometry等属性。而动画的控件必须是QObject类的派生类,其实大部分控件都是QObject的派生类。我们可以通过指定属性的初始值和终值,比如初始的大小和结束的大小,初始的位置和结束的位置,初始的颜色和结束的颜色等。如果未指定初始值,属性就会被设定为生成控件实例时那个值。
头文件
前两个是工程建好就有的,第三个是为了新建按钮,第四个是为了新建动画。
坐标系
以下表示位置的坐标系定义如下图所示。
实现动画的简单步骤
1.实例化QPropertyAnimation对象。
2.绑定要实现动画的对象,该对象要继承于QObject父类。
3.设置要进行变化的属性,尺寸、位置‘颜色等。
4.设置属性的起始值和终止值。
5.设置动画运行时长。
6.启动动画。
下面的示例都具有这六个步骤。而实例化对象、绑定对象、设置属性有两种方式进行操作。
第一种方式是直接通过构造函数一步到位,如下图所示。
第二种方式是分开进行,如下图所示。先实例化对象命名为Anima,然后通过setTargetObject函数和setPropertyName函数进行后两步。quit是一个创建好指向按钮的指针。
缩放
通过修改控件的geometry属性可以实现缩放效果,也可以实现位移的动画,该属性的前两个值确定了控件左上角的位置,后两个值确定了控件的大小。必须用QRcet来表示,有两种表示方式。我们选择第一种。
前面创建了一个QPushButton对象,用于动画的演示效果。setDuration设定的是动画的时间。
位移
如果只是需要位移动画的话,修改控件的pos属性即可。pos属性就是控件的左上角所在的位置。QPoint表示的是某一个点。
动画速度曲线
动画运动的速度曲线是可以更改的,默认是匀速运动。通过其成员函数setEasingCurve函数可以实现更改速度曲线的功能。在说明手册可以看到曲线的取值有哪些。
Anima->setEasingCurve(QEasingCurve::InOutQuad);
第一个Linear是默认的线性运动,速度是保持一定的。第二个InQuad曲线是二次函数曲线。下面还有很多,我就不列举了。可以通过一下方式查看曲线的取值。
鼠标放在函数处,按键盘上的F1;
再按一下红色框部分,就可以跳转到曲线介绍那里。
演示
通过信号与槽机制,建立按键与动画之间的联动关系,实现演示效果。代码如下:
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QPropertyAnimation>
#include <QMessageBox>
QPropertyAnimation *Anima = new QPropertyAnimation;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//定义一个按键
QPushButton *button1 = new QPushButton("缩放",this);
//将点击信号关联到槽函数
connect(button1,SIGNAL(pressed()),this,SLOT(suofang()));
button1->setGeometry(20,20,100,40);
QPushButton *button2 = new QPushButton("位移(默认曲线)",this);
connect(button2,SIGNAL(pressed()),this,SLOT(ChangePos()));
button2->setGeometry(130,20,100,40);
QPushButton *button3 = new QPushButton("位移(Cubic曲线)",this);
connect(button3,SIGNAL(pressed()),this,SLOT(ChangePos2()));
button3->setGeometry(240,20,100,40);
QPushButton *quit= new QPushButton("A",this);
quit->setGeometry(10,200,30,30);
Anima->setTargetObject(quit);
}
Widget::~Widget()
{
delete ui;
}
void Widget::suofang()
{
Anima->setPropertyName("geometry");
Anima ->setDuration(1000);
Anima ->setStartValue(QRect(10,200,10,10));
Anima ->setEndValue(QRect(10,200,200, 200));
Anima ->start();
}
void Widget::ChangePos()
{
Anima->setPropertyName("pos");
Anima ->setDuration(1000);
Anima ->setStartValue(QPoint(10,200));
Anima ->setEndValue(QPoint(500,200));
Anima ->start();
}
void Widget::ChangePos2()
{
Anima->setPropertyName("pos");
Anima ->setDuration(1000);
Anima ->setStartValue(QPoint(10,200));
Anima ->setEndValue(QPoint(500,200));
Anima->setEasingCurve(QEasingCurve::InOutCubic);
Anima ->start();
}
槽函数必须要在widget.h进行函数声明。
通过演示,可以明显看到默认速度曲线和Cubic曲线运动的不同。
插值运动
前面讲的都是从A点运动到B点,而路线都是直线的,一步到位。那假如我们需要它在中途经过C点,就会需要关键点插值函数。给定帧的范围必须要在0-1,也就是把整个运动过程看做1,如果需要在一半的时候插入关键帧,那就是0.5.
示例如下,在0.5处,即一半路程时插入关键帧。
动画的暂停与恢复
把上面的演示程序改一下,加入暂停和恢复函数。这个功能可以考虑用在agv的停车载货和卸货这个步骤。
这两个函数其实是他们的父类QAbstactAnimation的成员函数。
动画结束信号
我们希望动画执行结束之后发出一个信号,这个信号可以让我去做其他的事情。实际上QT已经内置了这个信号,接下来看看如何使用?设置信号与槽,用connect函数连接。第一个函数参数是动画对象Anima,第二个是QT规定的结束信号。
Anima_Finished函数就是我自定义的槽函数,名字可以任意取。
通过手册可以看到,当动画自然结束时(相对的概念就是强制停止),这个信号会发出。这个动画还有其他几个信号,表示停止、启动、运行中。
实验:
收到结束信号,就简单显示一个对话框。
验证成功。