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

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

前言

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

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

相关推荐
范纹杉想快点毕业14 小时前
C++抽象类与多态实战解析
java·c语言·开发语言·c++·python·qt
行云流水剑16 小时前
【学习记录】快速上手 PyQt6:设置 Qt Designer、PyUIC 和 PyRCC 在 PyCharm中的应用
python·qt·学习·pycharm
OldField-Tian18 小时前
Qt中使用正则表达式来提取字符串
qt·正则表达式
感叹号的豆浆20 小时前
使用qt 定义全局钩子 捕获系统的键盘事件
qt·计算机外设
hvinsion21 小时前
【开源工具】 黑客帝国系列系统监控工具:基于PyQt5的全方位资源监控系统
python·qt·开源·系统监控·数字雨·黑客帝国·psutil
old_power1 天前
VSCode 工作区配置文件通用模板(CMake + Ninja + MinGW/GCC 编译器 的 C++ 或 Qt 项目)
c++·vscode·qt
hvinsion1 天前
【开源工具】基于PyQt5工作时长计算器工具开发全解析
开发语言·python·qt·开源·时间·time·工作时长计算
最爱大盘鸡1 天前
使用PyQt5的图形用户界面(GUI)开发教程
开发语言·qt
csdndenglu1 天前
QT 5.9.2+VTK8.0实现等高线绘制
开发语言·qt
@Turbo@1 天前
【QT】QString& 与QString区别
开发语言·qt