文章目录
前言
在实际开发中,我们可以使某些小控件"运动"起来。这样可以使得"一动不动"的软件框架看起来更有"生机"。在Qt中有一个动画类很好用,下面是笔者根据QPropertyAnimation类设计出的一个可以旋转运动的齿轮。
一、准备
1.齿轮图片
我们需要一张齿轮的图片,图片复杂或者简单根据需求就行,建议图片要透明背景的。
2.编译环境
本文用到的是VS2017+Qt插件。本文代码涉及到的内容并不复杂,因此不是特别久远的版本都能够实现。
二、主要代码
1.静态图片的实现
我们可以以QGraphicsView作为控件载体,在QGraphicsScene上实现:
cpp
QGraphicsScene* pScene = new QGraphicsScene(this);
m_pUi->m_pPreGraphicsView->setRenderHint(QPainter::Antialiasing);
m_pUi->m_pPreGraphicsView->setScene(pScene);
将QPixmap贴图在QGraphicsPixmapItem上:
cpp
QPixmap pixmap("图片路径.png");
QGraphicsPixmapItem* m_pPixmapItem = new QGraphicsPixmapItem(pixmap);
m_pPixmapItem->setPos(x,y);//x,y为图片位置的坐标
pScene->addItem(m_pPixmapItem);//加载静态图片
至此,一张静态的图片完成。
2.动态匀速旋转图片的实现
我们需要重写QGraphicsPixmapItem
cpp
#include <QApplication>
#include <QGraphicsPixmapItem>
#include <QPropertyAnimation>
class ZAnimatedPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
explicit ZAnimatedPixmapItem(const QPixmap& pixmap);
virtual ~ZAnimatedPixmapItem();
private:
QPropertyAnimation *pAnimation = nullptr;
}
cpp
ZAnimatedPixmapItem::ZAnimatedPixmapItem(const QPixmap& pixmap)
: QGraphicsPixmapItem(pixmap)
{
this->setPixmap(pixmap);
this->setTransformOriginPoint(this->boundingRect().center());
pAnimation = new QPropertyAnimation(this, "rotation");
pAnimation->setDuration(3000);//设置动画时间为3秒
pAnimation->setEasingCurve(QEasingCurve::Linear);//设置匀速转动
pAnimation->setStartValue(0);
pAnimation->setEndValue(360);
pAnimation->setLoopCount(-1);//设置成-1是将该动画设置成无限循环
pAnimation->start();
}
至此一个匀速转动效果的动画实现了。适用于无限匀速转动齿轮的需求。
3.动态加速度旋转图片的实现
假如现在有更深一层的需求,需要通过某个事件触发动画开始以及动画结束,如果突然就匀速旋转或者急停,动画效果难免有些生硬。这个时候我们可以引入加速度和减速度:
cpp
pAnimation->setEasingCurve(QEasingCurve::InQuad);//设置加速转动
pAnimation->setEasingCurve(QEasingCurve::OutQuad);//设置减速转动
如果直接冒然将加速替换匀速是不可取的,这样的后果是在一个新周期开始时动画旋转速度是0,然后到动画结束最快,然后速度突然降为0,周而复始。
为了让动画显示更具观赏性,我们需要在动画开始事件触发时的第一个周期,动画加速旋转。第一个周期结束后,动画匀速旋转,在触发了动画关闭事件后的下一个周期,动画开始减速旋转直到周期结束。
因此,我们需要保证在动画每次完成一轮后都会触发一次事件,用来观察下一个动画中期齿轮应该进行的动画。
cpp
class ZAnimatedPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
explicit ZAnimatedPixmapItem(const QPixmap& pixmap);
virtual ~ZAnimatedPixmapItem();
void StartAnimation();
void StopAnimation();
int nStatus = 0;//齿轮的运动状态,由旋转事件决定
int completedLoops = 0;//周期结束后下一个周期做什么的判断依据
int runflag = 0;//是否在进行动画
private slots:
void onAnimationFinished();
private:
QPropertyAnimation *pAnimation = nullptr;
}
cpp
ZAnimatedPixmapItem::ZAnimatedPixmapItem(const QPixmap& pixmap)
: QGraphicsPixmapItem(pixmap)
{
this->setPixmap(pixmap);
this->setTransformOriginPoint(this->boundingRect().center());
pAnimation = new QPropertyAnimation(this, "rotation");
pAnimation->setStartValue(0);
pAnimation->setEndValue(360);
pAnimation->setLoopCount(1);//每完成一个周期都需要进行判断,因此只能将转动周期设置成1
QObject::connect(pAnimation, &QPropertyAnimation::finished, this, &ZAnimatedPixmapItem::onAnimationFinished);
}
void ZAnimatedPixmapItem::StartAnimation()
{
nStatus = 1;
if (0 == completedLoops && 0 == runflag)
{
completedLoops = 1;
pAnimation->setDuration(3000);
pAnimation->setEasingCurve(QEasingCurve::InQuad);
runflag = 1;
pAnimation->start();
}
}
void ZAnimatedPixmapItem::StopAnimation()
{
nStatus = 0;
}
void ZAnimatedPixmapItem::onAnimationFinished()
{
runflag = 0;
switch (completedLoops)
{
case 0:
if(0 != nStatus)
{
comletedLoops = 1;
pAnimation->setDuration(3000);
pAnimation->setEasingCurve(QEasingCurve::InQuad);
runflag = 1;
pAnimation->start();
}
break;
case 1:
if(0 == nStatus)
{
pAnimation->setDuration(3000);
pAnimation->setEasingCurve(QEasingCurve::OutQuad);
runflag = 1;
pAnimation->start();
comletedLoops = 0;
}
else
{
pAnimation->setDuration(2000);
pAnimation->setEasingCurve(QEasingCurve::Linear);
runflag = 1;
pAnimation->start();
comletedLoops = 2;
}
break;
case 2:
if(0 == nStatus)
{
pAnimation->setDuration(3000);
pAnimation->setEasingCurve(QEasingCurve::OutQuad);
runflag = 1;
pAnimation->start();
comletedLoops = 0;
}
else
{
runflag = 1;
pAnimation->start();
}
break;
default:
break;
}
}
至此一个可以加速减速转动效果的动画实现了。