动态加速旋转齿轮的实现优化版

动态加速旋转齿轮的实现优化版

前言

和上一次"开荒"随心写的相比,这一篇更加注重代码规范以及逻辑优化。

在实际开发中,我们可以使某些小控件"运动"起来。这样可以使得"一动不动"的软件框架看起来更有"生机"。在Qt中有一个动画类很好用,下面是笔者根据QPropertyAnimation类设计出的一个可以旋转运动的齿轮。

准备

齿轮图片:我们需要一张齿轮的图片,图片复杂或者简单根据需求就行,建议图片要透明背景的。

VS2017+Qt插件。

设计方案

静态图片的实现

最基本的UI贴图,我们可以以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为图片在QGraphicsScene上的坐标位置
m_pScene->addItem(m_pPixmapItem);

至此,一张静态的图片完成。

动态匀速旋转图片的实现

就如前言所说,有时候静态的贴图会使得整个UI界面显得生硬,我们需要引入一些动画,当需要引入动画时,我们需要重写QGraphicsPixmapItem,为了方便演示先简单的写出如下类:

MyAnimatedPixmapItem头文件:

cpp 复制代码
#include <QApplication>
#include <QGraphicsPixmapItem>
#include <QPropertyAnimation>
class MyAnimatedPixmapItem : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT
    Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
public:
	explicit MyAnimatedPixmapItem(const QPixmap &pixmap);
	virtual ~MyAnimatedPixmapItem();
private:
	QPropertyAnimation *m_pAnimation = nullptr;
}

MyAnimatedPixmapItem源文件:

cpp 复制代码
#include "MyAnimatedPixmapItem.h"

const int INT_ZERO          = 0;
const int INT_CIRCLE_TIME   = 3000;
const int INT_ONE_CIRCLE    = 360;
const int INT_INFINITE_TIME = -1;

MyAnimatedPixmapItem::MyAnimatedPixmapItem(const QPixmap &pixmap)
: QGraphicsPixmapItem(pixmap)
{
	this->setPixmap(pixmap);
	this->setTransformOriginPoint(this->boundingRect().center());
	m_pAnimation = new QPropertyAnimation(this, "rotation");
	m_pAnimation->setDuration(INT_CIRCLE_TIME);//设置动画时间(转动一圈)
	m_pAnimation->setEasingCurve(QEasingCurve::Linear);//设置匀速转动
	m_pAnimation->setStartValue(INT_ZERO);
	m_pAnimation->setEndValue(INT_ONE_CIRCLE);
	m_pAnimation->setLoopCount(INT_INFINITE_TIME);//设置成无限循环
	m_pAnimation->start();
}

需要注意的是:

①需要调用setEasingCurve(QEasingCurve::Linear)将动画模式设置成匀速旋转。

②需要调用setLoopCount(-1)将该动画设置成无限循环。

至此一个匀速转动效果的动画实现了,适用于无限匀速转动齿轮的需求。

动态匀速旋转图片的实现

如果需求是贴图能够停止能够运动,这样突然就匀速旋转或者急停,动画效果难免有些不连贯。假如现在有更深一层的需求,需要在动画开始时缓慢开始加速。这个时候我们可以引入加速度和减速度,可喜的是,Qt的官方函数已经给我们封装好了加速动画和减速动画:

cpp 复制代码
pAnimation->setEasingCurve(QEasingCurve::InQuad);//设置加速运动
pAnimation->setEasingCurve(QEasingCurve::OutQuad);//设置减速运动

如果直接冒然将加速替换匀速是不可取的,这样的后果是在一个新周期开始时动画旋转速度是0,然后到动画结束最快,然后速度突然降为0,周而复始。

为了让动画显示更具观赏性,我们需要在动画开始事件触发时的第一个周期,动画加速旋转。第一个周期结束后,动画匀速旋转,在触发了动画关闭事件后的下一个周期,动画开始减速旋转直到周期结束。因此,我们需要保证在动画每次完成一轮后都会触发一次事件,用来观察下一个动画中期齿轮应该进行的动画。

因为真实状态可能(比如下位机向上位机传信号开始或停止动画)是瞬间的,而为了让动画更具备连贯性,需要在瞬间触发开始或者停止时有一个加速度到匀速或者减速度到停止的动画效果:

cpp 复制代码
void MyAnimatedPixmapItem::onAnimationFinished()
{
    switch (m_nRotationStatus)
    {
    case ENUM_ROTATION_STATUS_STOP:
    case ENUM_ROTATION_STATUS_DECELERATION:
        if(ENUM_TEST_STATUS_RUN == m_nTestStatus)
        {
        	m_pAnimation->setDuration(m_nDoubleRotationTime);
        	m_pAnimation->setEasingCurve(QEasingCurve::InQuad);
        	m_nRotationStatus = ENUM_ROTATION_STATUS_ACCELERATE;
        	m_pAnimation->start();
        }
        else if (ENUM_TEST_STATUS_STOP == m_nTestStatus)
        {
            m_nRotationStatus = ENUM_ROTATION_STATUS_STOP;
		}
		break;
	case ENUM_ROTATION_STATUS_ACCELERATE:
	case ENUM_ROTATION_STATUS_UNIFORM_SPEED:
		if (ENUM_TEST_STATUS_STOP == m_nTestStatus)
		{
			m_pAnimation->setDuration(m_nDoubleRotationTime);
			m_pAnimation->setEasingCurve(QEasingCurve::OutQuad);
			m_nRotationStatus = ENUM_ROTATION_STATUS_DECELERATION;
			m_pAnimation->start();
		}
		else if(ENUM_TEST_STATUS_RUN == m_nTestStatus)
		{
			m_pAnimation->setDuration(m_nRotationTime);
			m_pAnimation->setEasingCurve(QEasingCurve::Linear);
			m_nRotationStatus = ENUM_ROTATION_STATUS_UNIFORM_SPEED;
			m_pAnimation->start();
		}
		break;
	default;
		break;
}

有了刚刚的事件处理机制,在各种情况下接收到开始、停止指令时,在结束一轮动画之后都能连贯的进行下一轮动画:

极端情况1:刚刚开始就关闭

极端情况2:刚刚关闭又开始

相关推荐
混迹网络的权某9 分钟前
每天一道C语言精选编程题之求数字的每⼀位之和
c语言·开发语言·考研·算法·改行学it·1024程序员节
IronmanJay3 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
加载中loading...4 小时前
Linux线程安全(二)条件变量实现线程同步
linux·运维·服务器·c语言·1024程序员节
Wx120不知道取啥名4 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
biomooc5 小时前
R语言 | paletteer包:拥有2100多个调色板!
r语言·数据可视化·1024程序员节
Hello.Reader5 小时前
FFmpeg 深度教程音视频处理的终极工具
ffmpeg·1024程序员节
Y.O.U..6 小时前
STL学习-容器适配器
开发语言·c++·学习·stl·1024程序员节
就爱敲代码6 小时前
怎么理解ES6 Proxy
1024程序员节
憧憬一下6 小时前
input子系统的框架和重要数据结构详解
arm开发·嵌入式·c/c++·1024程序员节·linux驱动开发
三日看尽长安花6 小时前
【Tableau】
1024程序员节