VS+Qt插件,动态加速旋转齿轮的实现。

文章目录


前言

在实际开发中,我们可以使某些小控件"运动"起来。这样可以使得"一动不动"的软件框架看起来更有"生机"。在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;
    }
}

至此一个可以加速减速转动效果的动画实现了。


相关推荐
dialect_12 小时前
KMP算法
开发语言·c++·算法
总要学点什么13 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
听风吹等浪起14 小时前
第26章:ViT+InceptionDW+FocalLoss改进|CT骨折影像二分类完整Pytorch实现(含PyQt5推理GUI)
pytorch·qt·分类
ShineWinsu14 小时前
对于Qt:QRadioButton常见属性以及QButtonGroup的解析
数据库·c++·qt·microsoft·gui·qradiobutton·qbuttongroup
开开心心_Every14 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
chenbingjie_c15 小时前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++
吴卫斌15 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
超级架构师16 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
叼烟扛炮16 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
LMT流氓兔17 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节