MFC转QT:Qt高级特性 - 动画框架(mfc程序转qt)
ccwgpt 2025-06-30 15:00 13 浏览 0 评论
Qt动画框架概述
Qt提供了一套功能强大的动画框架,可以为应用程序添加流畅、生动的用户界面效果。这套框架比MFC的动画能力强大许多,能够以声明式方法创建复杂的动画效果。
核心组件
Qt动画框架主要包含以下核心类:
- QPropertyAnimation - 基于属性的动画
- QVariantAnimation - 处理QVariant值变化的动画
- QAnimationGroup - 用于组合和控制多个动画
- QSequentialAnimationGroup - 顺序执行的动画组
- QParallelAnimationGroup - 并行执行的动画组
- QAbstractAnimation - 所有动画类的基类
- QEasingCurve - 提供多种缓动曲线控制动画速率变化
与MFC的对比
功能 | Qt动画框架 | MFC中的实现 |
基础框架 | 完整的动画系统 | 无直接支持,需自行实现 |
属性动画 | QPropertyAnimation | 需手动实现计时器和绘制 |
组合动画 | 动画组类 | 需完全自定义 |
缓动曲线 | 内置30多种缓动效果 | 需自行计算 |
状态机集成 | QStateMachine可与动画结合 | 无类似功能 |
易用性 | 声明式API,少量代码 | 需大量代码实现简单效果 |
基本动画
属性动画
QPropertyAnimation是最常用的动画类,它通过动画化Qt对象的属性值来创建效果:
// 按钮透明度变化动画
QPushButton *button = new QPushButton("动画按钮", this);
QPropertyAnimation *animation = new QPropertyAnimation(button, "opacity");
animation->setDuration(1000); // 持续1秒
animation->setStartValue(0.0); // 起始值(完全透明)
animation->setEndValue(1.0); // 结束值(完全不透明)
animation->start(); // 启动动画
位置和大小动画
常见的UI元素动画:
// 位置动画
QPropertyAnimation *posAnim = new QPropertyAnimation(widget, "geometry");
posAnim->setDuration(1500);
posAnim->setStartValue(QRect(0, 0, 100, 30));
posAnim->setEndValue(QRect(200, 200, 100, 30));
posAnim->setEasingCurve(QEasingCurve::OutBounce); // 弹跳效果
posAnim->start();
// 大小动画
QPropertyAnimation *sizeAnim = new QPropertyAnimation(widget, "size");
sizeAnim->setDuration(800);
sizeAnim->setStartValue(QSize(100, 30));
sizeAnim->setEndValue(QSize(200, 60));
sizeAnim->start();
颜色动画
class ColorWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
ColorWidget(QWidget *parent = nullptr) : QWidget(parent), m_color(Qt::red)
{
setMinimumSize(100, 100);
}
QColor color() const { return m_color; }
void setColor(const QColor &color)
{
m_color = color;
update(); // 触发重绘
}
protected:
void paintEvent(QPaintEvent *) override
{
QPainter painter(this);
painter.fillRect(rect(), m_color);
}
private:
QColor m_color;
};
// 使用颜色动画
ColorWidget *widget = new ColorWidget(this);
QPropertyAnimation *colorAnim = new QPropertyAnimation(widget, "color");
colorAnim->setDuration(2000);
colorAnim->setStartValue(QColor(255, 0, 0)); // 红色
colorAnim->setEndValue(QColor(0, 0, 255)); // 蓝色
colorAnim->start();
使用缓动曲线
QEasingCurve提供多种缓动效果控制动画的变化速率:
// 几种常用的缓动曲线
animation->setEasingCurve(QEasingCurve::Linear); // 线性变化
animation->setEasingCurve(QEasingCurve::InOutQuad); // 二次加减速
animation->setEasingCurve(QEasingCurve::OutBounce); // 弹跳效果
animation->setEasingCurve(QEasingCurve::InOutElastic); // 弹性效果
animation->setEasingCurve(QEasingCurve::OutBack); // 回弹效果
// 自定义缓动曲线
QEasingCurve customCurve(QEasingCurve::InOutCirc);
customCurve.setAmplitude(1.5); // 设置振幅
customCurve.setPeriod(0.5); // 设置周期
animation->setEasingCurve(customCurve);
循环动画
// 设置循环次数(-1表示无限循环)
animation->setLoopCount(3); // 循环3次
animation->setLoopCount(-1); // 无限循环
// 设置循环方向
animation->setDirection(QPropertyAnimation::Forward); // 只向前
animation->setDirection(QPropertyAnimation::Backward); // 只向后
animation->setDirection(QPropertyAnimation::ForwardBackward); // 来回播放(乒乓模式)
复合动画
顺序动画
QSequentialAnimationGroup可以按顺序播放多个动画:
// 创建按钮
QPushButton *button = new QPushButton("动画按钮", this);
button->move(50, 50);
// 创建顺序动画组
QSequentialAnimationGroup *seqGroup = new QSequentialAnimationGroup(this);
// 添加位置动画
QPropertyAnimation *posAnim1 = new QPropertyAnimation(button, "pos");
posAnim1->setDuration(1000);
posAnim1->setStartValue(QPoint(50, 50));
posAnim1->setEndValue(QPoint(200, 50));
seqGroup->addAnimation(posAnim1);
// 添加颜色动画(假设按钮有color属性)
QPropertyAnimation *colorAnim = new QPropertyAnimation(button, "styleSheet");
colorAnim->setDuration(1000);
colorAnim->setStartValue("background-color: blue;");
colorAnim->setEndValue("background-color: red;");
seqGroup->addAnimation(colorAnim);
// 添加另一个位置动画
QPropertyAnimation *posAnim2 = new QPropertyAnimation(button, "pos");
posAnim2->setDuration(1000);
posAnim2->setStartValue(QPoint(200, 50));
posAnim2->setEndValue(QPoint(200, 200));
seqGroup->addAnimation(posAnim2);
// 启动顺序动画组
seqGroup->start();
并行动画
QParallelAnimationGroup可以同时播放多个动画:
// 创建并行动画组
QParallelAnimationGroup *parGroup = new QParallelAnimationGroup(this);
// 添加位置动画
QPropertyAnimation *posAnim = new QPropertyAnimation(widget, "pos");
posAnim->setDuration(1500);
posAnim->setStartValue(QPoint(50, 50));
posAnim->setEndValue(QPoint(200, 200));
parGroup->addAnimation(posAnim);
// 添加大小动画
QPropertyAnimation *sizeAnim = new QPropertyAnimation(widget, "size");
sizeAnim->setDuration(1500);
sizeAnim->setStartValue(QSize(100, 30));
sizeAnim->setEndValue(QSize(200, 60));
parGroup->addAnimation(sizeAnim);
// 添加旋转动画(假设widget有rotation属性)
QPropertyAnimation *rotAnim = new QPropertyAnimation(widget, "rotation");
rotAnim->setDuration(1500);
rotAnim->setStartValue(0);
rotAnim->setEndValue(360);
parGroup->addAnimation(rotAnim);
// 启动并行动画组
parGroup->start();
嵌套动画组
动画组可以嵌套,创建复杂的动画序列:
// 创建主顺序动画组
QSequentialAnimationGroup *mainGroup = new QSequentialAnimationGroup(this);
// 添加第一个动画
QPropertyAnimation *anim1 = new QPropertyAnimation(widget, "pos");
anim1->setDuration(1000);
anim1->setStartValue(QPoint(0, 0));
anim1->setEndValue(QPoint(100, 0));
mainGroup->addAnimation(anim1);
// 添加一个并行动画组作为第二步
QParallelAnimationGroup *parGroup = new QParallelAnimationGroup;
mainGroup->addAnimation(parGroup);
// 在并行组中添加动画
QPropertyAnimation *anim2 = new QPropertyAnimation(widget, "pos");
anim2->setDuration(1000);
anim2->setStartValue(QPoint(100, 0));
anim2->setEndValue(QPoint(100, 100));
parGroup->addAnimation(anim2);
QPropertyAnimation *anim3 = new QPropertyAnimation(widget, "size");
anim3->setDuration(1000);
anim3->setStartValue(QSize(50, 50));
anim3->setEndValue(QSize(100, 100));
parGroup->addAnimation(anim3);
// 添加第三个动画
QPropertyAnimation *anim4 = new QPropertyAnimation(widget, "pos");
anim4->setDuration(1000);
anim4->setStartValue(QPoint(100, 100));
anim4->setEndValue(QPoint(0, 100));
mainGroup->addAnimation(anim4);
// 添加第四个动画
QPropertyAnimation *anim5 = new QPropertyAnimation(widget, "pos");
anim5->setDuration(1000);
anim5->setStartValue(QPoint(0, 100));
anim5->setEndValue(QPoint(0, 0));
mainGroup->addAnimation(anim5);
// 启动整个动画序列
mainGroup->start();
动画控制
基本控制
动画的基本控制操作:
animation->start(); // 启动动画
animation->pause(); // 暂停动画
animation->resume(); // 恢复暂停的动画
animation->stop(); // 停止动画
// 动画方向
animation->setDirection(QPropertyAnimation::Forward); // 正向
animation->setDirection(QPropertyAnimation::Backward); // 反向
// 更新动画持续时间
animation->setDuration(2000); // 2秒
动画状态监控
// 使用信号槽监控动画状态
connect(animation, &QPropertyAnimation::finished, this, &MyWidget::onAnimationFinished);
connect(animation, &QPropertyAnimation::stateChanged, this, &MyWidget::onStateChanged);
connect(animation, &QPropertyAnimation::currentLoopChanged, this, &MyWidget::onLoopChanged);
// 状态改变处理函数
void MyWidget::onStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
switch (newState) {
case QAbstractAnimation::Running:
qDebug() << "动画开始运行";
break;
case QAbstractAnimation::Paused:
qDebug() << "动画已暂停";
break;
case QAbstractAnimation::Stopped:
qDebug() << "动画已停止";
break;
}
}
// 可以通过状态查询
if (animation->state() == QAbstractAnimation::Running) {
// 动画正在运行
}
关键帧动画
关键帧允许在动画过程中定义多个中间点:
QPropertyAnimation *animation = new QPropertyAnimation(widget, "pos");
animation->setDuration(3000);
// 设置关键帧
animation->setKeyValueAt(0, QPoint(0, 0)); // 0% - 起点
animation->setKeyValueAt(0.3, QPoint(100, 0)); // 30% - 第一个关键点
animation->setKeyValueAt(0.5, QPoint(100, 100)); // 50% - 第二个关键点
animation->setKeyValueAt(0.8, QPoint(50, 50)); // 80% - 第三个关键点
animation->setKeyValueAt(1, QPoint(0, 0)); // 100% - 终点
// 可以为不同段设置不同的缓动曲线
animation->setEasingCurve(QEasingCurve::OutElastic);
animation->start();
高级应用
自定义可动画属性
使用Qt的属性系统创建自定义动画属性:
class CustomWidget : public QWidget
{
Q_OBJECT
// 声明自定义属性
Q_PROPERTY(qreal progress READ progress WRITE setProgress)
Q_PROPERTY(QPointF centerPoint READ centerPoint WRITE setCenterPoint)
public:
CustomWidget(QWidget *parent = nullptr) : QWidget(parent), m_progress(0), m_centerPoint(0, 0)
{
setMinimumSize(200, 200);
}
qreal progress() const { return m_progress; }
void setProgress(qreal progress)
{
m_progress = progress;
update(); // 触发重绘
}
QPointF centerPoint() const { return m_centerPoint; }
void setCenterPoint(const QPointF &point)
{
m_centerPoint = point;
update();
}
protected:
void paintEvent(QPaintEvent *) override
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// 使用progress属性控制圆的半径
int radius = int(m_progress * 100);
painter.setBrush(Qt::blue);
painter.drawEllipse(m_centerPoint, radius, radius);
}
private:
qreal m_progress;
QPointF m_centerPoint;
};
// 使用自定义属性动画
CustomWidget *widget = new CustomWidget(this);
widget->resize(300, 300);
// 进度动画
QPropertyAnimation *progressAnim = new QPropertyAnimation(widget, "progress");
progressAnim->setDuration(1500);
progressAnim->setStartValue(0.0);
progressAnim->setEndValue(1.0);
progressAnim->setEasingCurve(QEasingCurve::OutCubic);
// 中心点动画
QPropertyAnimation *centerAnim = new QPropertyAnimation(widget, "centerPoint");
centerAnim->setDuration(1500);
centerAnim->setStartValue(QPointF(50, 50));
centerAnim->setEndValue(QPointF(250, 250));
centerAnim->setEasingCurve(QEasingCurve::OutBounce);
// 创建并行动画组
QParallelAnimationGroup *group = new QParallelAnimationGroup(this);
group->addAnimation(progressAnim);
group->addAnimation(centerAnim);
group->start();
状态机动画
结合QStateMachine和动画框架可以创建基于状态的UI动画:
// 创建一个按钮
QPushButton *button = new QPushButton("状态动画", this);
button->setGeometry(30, 30, 100, 30);
// 创建状态机
QStateMachine *machine = new QStateMachine(this);
// 创建两个状态
QState *state1 = new QState(machine);
QState *state2 = new QState(machine);
// 为状态1设置属性
state1->assignProperty(button, "geometry", QRect(30, 30, 100, 30));
state1->assignProperty(button, "styleSheet", "background-color: blue;");
// 为状态2设置属性
state2->assignProperty(button, "geometry", QRect(200, 200, 150, 50));
state2->assignProperty(button, "styleSheet", "background-color: red;");
// 添加状态转换条件
state1->addTransition(button, &QPushButton::clicked, state2);
state2->addTransition(button, &QPushButton::clicked, state1);
// 创建动画配置
QPropertyAnimation *animation1 = new QPropertyAnimation(button, "geometry");
animation1->setDuration(1000);
animation1->setEasingCurve(QEasingCurve::OutBounce);
QPropertyAnimation *animation2 = new QPropertyAnimation(button, "styleSheet");
animation2->setDuration(1000);
// 创建并行动画组
QParallelAnimationGroup *animGroup = new QParallelAnimationGroup;
animGroup->addAnimation(animation1);
animGroup->addAnimation(animation2);
// 为状态转换设置动画
state1->addTransition(button, &QPushButton::clicked, state2)->addAnimation(animGroup);
state2->addTransition(button, &QPushButton::clicked, state1)->addAnimation(animGroup);
// 设置初始状态并启动状态机
machine->setInitialState(state1);
machine->start();
使用QML动画
对于更复杂的UI动画,可以考虑使用QML,它提供了更简洁的动画语法:
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
width: 400
height: 400
color: "lightgray"
Rectangle {
id: animRect
width: 100
height: 100
color: "blue"
// 定义属性动画
PropertyAnimation {
id: moveAnimation
target: animRect
property: "x"
from: 0
to: 300
duration: 1000
easing.type: Easing.OutBounce
}
PropertyAnimation {
id: colorAnimation
target: animRect
property: "color"
from: "blue"
to: "red"
duration: 1000
}
// 点击触发动画
MouseArea {
anchors.fill: parent
onClicked: {
moveAnimation.start()
colorAnimation.start()
}
}
}
}
在C++中加载QML:
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
实用技巧与最佳实践
- 缓存最终状态:对于复杂动画,保存动画结束时的状态
// 动画结束时保存状态
connect(animation, &QPropertyAnimation::finished, [=]() {
finalValue = animation->endValue();
});
- 避免过度动画:不要让界面充斥太多动画
// 提供禁用动画的选项
bool animationsEnabled = true; // 可通过设置选项控制
if (animationsEnabled) {
animation->start();
} else {
// 直接设置最终值,不使用动画
widget->setProperty(animation->propertyName(), animation->endValue());
}
- 使用动画组合特效:
// 创建淡入淡出效果
void fadeWidgetIn(QWidget *widget, int duration = 500)
{
widget->setWindowOpacity(0.0);
widget->show();
QPropertyAnimation *animation = new QPropertyAnimation(widget, "windowOpacity");
animation->setDuration(duration);
animation->setStartValue(0.0);
animation->setEndValue(1.0);
animation->setEasingCurve(QEasingCurve::InOutQuad);
animation->start(QPropertyAnimation::DeleteWhenStopped);
}
void fadeWidgetOut(QWidget *widget, int duration = 500)
{
QPropertyAnimation *animation = new QPropertyAnimation(widget, "windowOpacity");
animation->setDuration(duration);
animation->setStartValue(1.0);
animation->setEndValue(0.0);
animation->setEasingCurve(QEasingCurve::InOutQuad);
connect(animation, &QPropertyAnimation::finished, widget, &QWidget::hide);
animation->start(QPropertyAnimation::DeleteWhenStopped);
}
- 性能考虑:
- 减少同时运行的动画数量
- 对于复杂动画,使用QtQuick/QML可能提供更好的性能
- 对GPU加速的支持 (OpenGL)
// 启用OpenGL渲染
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
QSurfaceFormat::setDefaultFormat(format);
从MFC迁移的建议
1. 功能映射
MFC实现 | Qt动画框架 |
使用计时器的自定义动画 | QPropertyAnimation |
手动计算线性动画 | QEasingCurve提供多种曲线 |
自行维护动画状态 | 使用signals/slots监控状态 |
复杂动画需编写大量代码 | 使用动画组简化复杂动画 |
无状态机集成 | QStateMachine与动画集成 |
自定义绘制实现动画 | QtQuick/QML声明式动画 |
2. 迁移策略
- 识别动画需求: 确定应用中需要动画的UI元素和交互
- 替换计时器代码: 使用Qt的属性动画系统替换基于计时器的动画代码
- 利用缓动曲线: 使用预定义的缓动曲线替代手动计算的平滑效果
- 分组动画: 使用动画组管理复杂的动画序列
- 考虑状态机: 对于状态变化引起的UI更新,考虑使用状态机
- 评估QML: 对于非常复杂的UI动画,考虑使用QML
3. 常见陷阱
- 过度使用动画: 避免在所有UI元素上都添加动画
- 动画性能: 复杂动画可能影响性能,应进行适当测试
- 内存管理: 注意动画对象的生命周期管理
- 多平台考虑: 在不同平台上测试动画效果
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)