动画框架
动画框架提供了一种简便的方法来为您的GUI元素添加动画效果。它允许您对小部件的Qt属性值或QObject 进行动画处理。该框架提供的绝大多数功能在 Qt Quick中同样可用,您可以在其中以声明式的方式定义动画。
本概述介绍了该框架的架构,并通过示例演示了用于对QObject 和GUI元素进行动画处理的常用技术。
动画架构
下图展示了该框架提供的最重要的类:

其中包括 `QAbstractAnimation ` 类,该类为动画提供了必要的基础。该类定义了框架支持的所有动画的通用属性,例如启动、停止和暂停动画的能力。该类还会接收时间变化通知。
该框架还提供了QVariantAnimation 和QAnimationGroup 类,它们基于其基类QAbstractAnimation 构建。在继承层次中,接下来是QPropertyAnimation ,该类继承自QVariantAnimation ,它允许您对小部件的Qt属性或QObject 进行动画处理。该类使用缓入缓出曲线对属性值进行插值。 有了这些,您只需一个QObject 类,其中包含一个可进行动画处理的Qt属性值即可。
可以通过构建QAbstractAnimation的树结构来构建复杂的动画,其中该树是一个QAnimationGroup ,它包含其他动画。这些动画组还可以包含代表不同组或动画的子组,例如QParallelAnimationGroup 和QSequentialAnimationGroup 。
在后台,所有动画均由一个全局计时器控制,该计时器会向updates 发送有关所有正在运行的动画的信息。
有关这些单个类及其在框架中作用的详细信息,请参阅其文档。
框架提供的类
这些类为创建简单和复杂的动画提供了必要的基础架构。
所有动画的基础 | |
动画组的抽象基类 | |
用于控制动画的缓动曲线 | |
并行动画组 | |
QSequentialAnimationGroup 的暂停功能 | |
对 Qt 属性进行动画处理 | |
顺序动画组 | |
用于控制动画的时间轴 | |
动画的基类 |
Qt属性的动画效果
由于QPropertyAnimation 类能够对Qt属性进行插值,因此被广泛使用。实际上,其父类——QVariantAnimation——提供了updateCurrentValue()的抽象实现,除非你在valueChanged signal 上进行修改,否则该方法不会改变任何值。
该框架允许您对 Qt 中现有类的 Qt 属性进行动画处理。例如,QWidget 类(可嵌入到QGraphicsView中)具有边界、颜色等属性。以下示例演示了如何对QPushButton 控件进行动画处理:
#include <QApplication>
#include <QPushButton>
#include <QPropertyAnimation>
class MyButtonWidget : public QWidget
{
public:
MyButtonWidget(QWidget *parent = nullptr);
};
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *button = new QPushButton(tr("Animated Button"), this);
QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this);
anim->setDuration(10000);
anim->setStartValue(QPoint(0, 0));
anim->setEndValue(QPoint(100, 250));
anim->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyButtonWidget buttonAnimWidget;
buttonAnimWidget.resize(QSize(800, 600));
buttonAnimWidget.show();
return a.exec();
}该示例对QPushButton 的pos Qt属性进行动画处理,使其在10秒(10000毫秒)内从屏幕左上角移动到终点位置(250, 250)。
该示例采用线性插值法来控制起始值与终点值之间的动画速度。不妨在起始值与终点值之间添加另一个数值,观察它们如何被插值。这次请使用QPropertyAnimation::setKeyValueAt()函数来添加这些数值:
...
anim->setDuration(10000);
anim->setKeyValueAt(0, QPoint(0, 0));
anim->setKeyValueAt(0.8, QPoint(250, 250));
anim->setKeyValueAt(1, QPoint(0, 0));
...在此示例中,动画在 8 秒内将按钮移动到 (250, 250),并在剩余的 2 秒内将其移回原始位置。按钮的移动在这些点之间采用线性插值。
如果某个QObject 的值未被声明为Qt属性,但该值具有setter方法,你也可以对其进行动画处理。在这种情况下,请从包含该值的类派生出一个新类,并为该值添加一个带有setter方法的Qt属性。
注意:每个 Qt 属性都需要一个获取器,因此如果尚未定义获取器,则应提供一个。
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
};在此示例中,MyGraphicsRectItem 继承自QGraphicsRectItem 和QObject ,并定义了pos 属性。即使QGraphicsRectItem 未提供pos 属性,您仍可对该项的pos 进行动画处理。
有关 Qt 属性系统的概述,请参阅Qt 的属性系统。
动画与图形视图框架
QPropertyAnimation 也可用于对不继承QObject 的QGraphicsItem 进行动画处理。在这种情况下,您需要从要进行动画处理的图形项派生一个类。该派生类还应继承自QObject ,以便能够在QGraphicsItem 上使用QPropertyAnimation 。以下示例演示了具体实现方法:
class Pixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
...
}注意:您 也可以继承自QGraphicsWidget ,该类本身已经是QObject 。
如上一节所述,您需要定义要进行动画处理的属性。由于元对象系统的要求,派生类必须首先继承自QObject 。
缓动曲线
QPropertyAnimation 会在起始属性值和结束属性值之间进行线性插值。除了在动画中添加更多关键帧值外,您还可以选择一条缓动曲线,在0到1的范围内控制插值速度,而无需改变路径。
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *button = new QPushButton(tr("Animated Button"), this);
QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this);
anim->setDuration(10000);
anim->setStartValue(QPoint(0, 0));
anim->setEndValue(QPoint(100, 250));
anim->setEasingCurve(QEasingCurve::OutBounce);
anim->start();
}在此示例中,动画遵循一条使button 像球一样弹跳的曲线。QEasingCurve 提供了丰富的曲线集合,可通过QEasingCurve::Type 枚举进行选择。若需使用未提供的其他曲线,请自行实现并将其注册到QEasingCurve 中。
动画分组
一个应用程序通常包含多个动画。例如,它可能需要同时移动多个图形项,或者让它们依次移动。
QAnimationGroup的子类——QSequentialAnimationGroup 和QParallelAnimationGroup——是其他动画的容器,因此这些动画可以按顺序或并行方式播放。QAnimationGroup 本身不执行属性动画,但会定期收到时间变化的通知。这使其能够将这些时间变化转发给动画组,由动画组控制各自动画的播放时机。
以下两个示例演示了QSequentialAnimationGroup 和QParallelAnimationGroup 的用法:
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *bonnie = new QPushButton(tr("Bonnie"), this);
QPushButton *clyde = new QPushButton(tr("Clyde"), this);
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this);
anim1->setDuration(3000);
anim1->setStartValue(QPoint(0, 0));
anim1->setEndValue(QPoint(100, 250));
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this);
anim2->setDuration(3000);
anim2->setStartValue(QPoint(100, 250));
anim2->setEndValue(QPoint(500, 500));
QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup;
parallelAnim->addAnimation(anim1);
parallelAnim->addAnimation(anim2);
parallelAnim->start();
}并行组可同时播放多个动画。其start() 函数会启动该组中的所有动画。
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *bonnie = new QPushButton(tr("Bonnie"), this);
QPushButton *clyde = new QPushButton(tr("Clyde"), this);
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this);
anim1->setDuration(3000);
anim1->setStartValue(QPoint(0, 0));
anim1->setEndValue(QPoint(100, 250));
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this);
anim2->setDuration(3000);
anim2->setStartValue(QPoint(0, 0));
anim2->setEndValue(QPoint(200, 250));
QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup;
sequenceAnim->addAnimation(anim1);
sequenceAnim->addAnimation(anim2);
sequenceAnim->start();
}顾名思义,序列组(QSequentialAnimationGroup )会按顺序播放其动画。当前一个动画播放完毕后,它会启动列表中的下一个动画。
一个组本身就是一段动画,因此你可以将其添加到另一个组中。通过这种方式,可以构建一个动画树,从而定义各段动画之间相互关联的播放顺序。
对象所有权
QPropertyAnimation 应始终有一个父对象来控制其生命周期。典型的应用可能包含多个分组动画,此时动画组将拥有这些动画的所有权。独立的QPropertyAnimation 必须显式指定一个父对象来控制其生命周期。在下面的示例中,您可以看到独立的QPropertyAnimation 将其父对象设为QApplication 实例:
#include <QApplication>
#include <QPushButton>
#include <QPropertyAnimation>
class MyButtonWidget : public QWidget
{
public:
MyButtonWidget(QWidget *parent = nullptr);
};
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *button = new QPushButton(tr("Animated Button"), this);
QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this);
anim->setDuration(10000);
anim->setStartValue(QPoint(0, 0));
anim->setEndValue(QPoint(100, 250));
anim->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyButtonWidget buttonAnimWidget;
buttonAnimWidget.resize(QSize(800, 600));
buttonAnimWidget.show();
return a.exec();
}注意:您 还可以在启动动画时选择一个delete policy 来控制动画的生命周期。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.