Qt进阶开发:动画框架的介绍和使用

一、QPropertyAnimation 简介

#include <QPropertyAnimation>
  • QPropertyAnimation 可以让你在一段时间内平滑地修改对象的属性值。
  • 支持 QWidget 的 geometry、pos、size、windowOpacity 等属性。
  • 它基于 Qt 的 属性系统(Q_PROPERTY),只能操作那些被 Q_PROPERTY 宏声明过的属性。

二、基本用法

例子:让一个按钮平滑移动位置

QPushButton *button = new QPushButton("Click Me", this);
button->move(0, 0);

QPropertyAnimation *animation = new QPropertyAnimation(button, "pos");
animation->setDuration(1000);                    // 动画持续 1000ms
animation->setStartValue(QPoint(0, 0));          // 起始位置
animation->setEndValue(QPoint(200, 200));        // 结束位置
animation->start();                              // 启动动画

例子:让一个按钮平滑移动并且变大

#include <QPushButton>
#include <QPropertyAnimation>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);

    QPushButton* pBtn = new QPushButton("Animated Button", this);
    QPropertyAnimation *pAnimation = new QPropertyAnimation(pBtn, "geometry");
    pAnimation->setDuration(1000);
    pAnimation->setStartValue(QRect(0, 0, 120, 30));
    pAnimation->setEndValue(QRect(250, 250, 200, 60));
    pAnimation->start(QAbstractAnimation::DeleteWhenStopped);

}

三、常用属性和方法

在这里插入图片描述

四、支持的属性(部分常用)

在这里插入图片描述

五、多个动画组合

  在一个应用中经常会包含多个动画,例如,要同时移动多个图形项或者让它们一个接一个地串行移动。使用QAnimationGroup类可以实现复杂的动画,它的两个子类 QSequentialAnimationGroup和QParallelAnimationGroup分别提供了串行动画组和并行动画组。

5.1 QParallelAnimationGroup 的使用
QParallelAnimationGroup 是 Qt 动画框架(Qt Animation Framework)中的一个类,用于并行执行多个动画,即多个属性动画同时发生。

#include <QParallelAnimationGroup>
  • 它继承自 QAnimationGroup。
  • 内部可以添加多个 QPropertyAnimation(或其它动画)。
  • 所有动画会同时启动,彼此独立但并行执行。

基本使用示例:
示例:按钮同时平移、缩放、透明度变化

QPushButton *button = new QPushButton("Animate", this);
button->resize(100, 30);
button->move(50, 50);

// 位置动画
QPropertyAnimation *posAnim = new QPropertyAnimation(button, "pos");
posAnim->setDuration(1000);
posAnim->setStartValue(QPoint(50, 50));
posAnim->setEndValue(QPoint(200, 150));

// 大小动画
QPropertyAnimation *sizeAnim = new QPropertyAnimation(button, "size");
sizeAnim->setDuration(1000);
sizeAnim->setStartValue(QSize(100, 30));
sizeAnim->setEndValue(QSize(200, 60));

// 透明度动画(需设置 WA_TranslucentBackground + setWindowOpacity)
QPropertyAnimation *opacityAnim = new QPropertyAnimation(button, "windowOpacity");
opacityAnim->setDuration(1000);
opacityAnim->setStartValue(1.0);
opacityAnim->setEndValue(0.3);

// 并行动画组
QParallelAnimationGroup *group = new QParallelAnimationGroup(this);
group->addAnimation(posAnim);
group->addAnimation(sizeAnim);
group->addAnimation(opacityAnim);

group->start();

常用方法和属性:
在这里插入图片描述

完整示例:

#include <QPushButton>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    QPushButton *button = new QPushButton("Animate Me", this);
    button->resize(100, 30);
    button->move(50, 50);

    // 动画 1:移动
    QPropertyAnimation *moveAnim = new QPropertyAnimation(button, "pos");
    moveAnim->setDuration(1000);
    moveAnim->setStartValue(QPoint(50, 50));
    moveAnim->setEndValue(QPoint(200, 150));

    // 动画 2:缩放
    QPropertyAnimation *sizeAnim = new QPropertyAnimation(button, "size");
    sizeAnim->setDuration(1000);
    sizeAnim->setStartValue(QSize(100, 30));
    sizeAnim->setEndValue(QSize(200, 60));

    // 动画 3:透明度
    QPropertyAnimation *opacityAnim = new QPropertyAnimation(button, "windowOpacity");
    opacityAnim->setDuration(1000);
    opacityAnim->setStartValue(1.0);
    opacityAnim->setEndValue(0.4);

    // 并行动画组
    QParallelAnimationGroup *group = new QParallelAnimationGroup;
    group->addAnimation(moveAnim);
    group->addAnimation(sizeAnim);
    group->addAnimation(opacityAnim);

    QObject::connect(button, &QPushButton::clicked, [group]() {
        group->start(QAbstractAnimation::KeepWhenStopped);
    });
}

5.2 QSequentialAnimationGroup 的使用
QSequentialAnimationGroup 是 Qt 动画框架(Qt Animation Framework)中的一个动画组类,用于 顺序地执行多个动画 —— 即一个动画结束后,自动执行下一个动画,依此类推。它特别适用于需要连续步骤式动画效果的场景,比如一个按钮先移动 → 再放大 → 再变淡。

#include <QSequentialAnimationGroup>
  • 它继承自 QAnimationGroup。
  • 内部包含多个动画(如 QPropertyAnimation)。
  • 每个动画顺序执行,一个结束后自动播放下一个。

基本使用示例:
示例:按钮先移动 → 再变大 → 再淡出

QPushButton *button = new QPushButton("Animate", this);
button->move(50, 50);
button->resize(100, 30);

// 动画 1:移动
QPropertyAnimation *moveAnim = new QPropertyAnimation(button, "pos");
moveAnim->setDuration(1000);
moveAnim->setStartValue(QPoint(50, 50));
moveAnim->setEndValue(QPoint(200, 150));

// 动画 2:缩放
QPropertyAnimation *sizeAnim = new QPropertyAnimation(button, "size");
sizeAnim->setDuration(800);
sizeAnim->setStartValue(QSize(100, 30));
sizeAnim->setEndValue(QSize(200, 60));

// 动画 3:透明度
QPropertyAnimation *opacityAnim = new QPropertyAnimation(button, "windowOpacity");
opacityAnim->setDuration(800);
opacityAnim->setStartValue(1.0);
opacityAnim->setEndValue(0.3);

// 顺序动画组
QSequentialAnimationGroup *group = new QSequentialAnimationGroup(this);
group->addAnimation(moveAnim);
group->addAnimation(sizeAnim);
group->addAnimation(opacityAnim);

group->start();

常用方法:
在这里插入图片描述
插入等待/暂停动画:
可以在两个动画之间插入暂停

group->addAnimation(moveAnim);
group->insertPause(500);  // 停 500ms
group->addAnimation(sizeAnim);

完整可运行示例:

#include <QPushButton>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    QPushButton *button = new QPushButton("Start Animation", this);
    button->move(50, 50);
    button->resize(100, 30);

    // 动画组定义
    QSequentialAnimationGroup *group = new QSequentialAnimationGroup;

    // 移动动画
    QPropertyAnimation *moveAnim = new QPropertyAnimation(button, "pos");
    moveAnim->setDuration(1000);
    moveAnim->setStartValue(QPoint(50, 50));
    moveAnim->setEndValue(QPoint(200, 150));

    // 暂停动画
    group->addAnimation(moveAnim);
    group->insertPause(1, 500);

    // 缩放动画
    QPropertyAnimation *sizeAnim = new QPropertyAnimation(button, "size");
    sizeAnim->setDuration(800);
    sizeAnim->setStartValue(QSize(100, 30));
    sizeAnim->setEndValue(QSize(200, 60));
    group->addAnimation(sizeAnim);

    // 透明度动画
    QPropertyAnimation *opacityAnim = new QPropertyAnimation(button, "windowOpacity");
    opacityAnim->setDuration(1000);
    opacityAnim->setStartValue(1.0);
    opacityAnim->setEndValue(0.3);
    group->addAnimation(opacityAnim);

    QObject::connect(button, &QPushButton::clicked, [group]() {
        group->start(QAbstractAnimation::KeepWhenStopped);
    });
}

补充说明:

  • 动画可重复播放:group->setLoopCount(n);
  • 动画结束信号:connect(group, &QSequentialAnimationGroup::finished, …)
  • 可嵌套其他动画组形成复杂流程(如先顺序 → 同时多个动画)

5.3 多个动画的使用实例
多个组件依次动画执行:

#include <QPushButton>
#include <QVBoxLayout>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    // 创建三个按钮
    QPushButton *btn1 = new QPushButton("Button 1", this);
    QPushButton *btn2 = new QPushButton("Button 2", this);
    QPushButton *btn3 = new QPushButton("Button 3", this);

    btn1->move(20, 50);
    btn2->move(20, 100);
    btn3->move(20, 150);

    // 创建动画组
    QSequentialAnimationGroup *group = new QSequentialAnimationGroup(this);

    // 按钮 1 动画
    QPropertyAnimation *anim1 = new QPropertyAnimation(btn1, "pos");
    anim1->setDuration(500);
    anim1->setEndValue(QPoint(250, 50));

    // 按钮 2 动画
    QPropertyAnimation *anim2 = new QPropertyAnimation(btn2, "pos");
    anim2->setDuration(500);
    anim2->setEndValue(QPoint(250, 100));

    // 按钮 3 动画
    QPropertyAnimation *anim3 = new QPropertyAnimation(btn3, "pos");
    anim3->setDuration(500);
    anim3->setEndValue(QPoint(250, 150));

    // 插入动画到顺序组
    group->addAnimation(anim1);
    group->addAnimation(anim2);
    group->addAnimation(anim3);

    // 点击任意按钮启动动画
    connect(btn1, &QPushButton::clicked, this, [=]{
        group->start();
    });
    connect(btn2, &QPushButton::clicked, this, [=]{
        group->start();
    });
    connect(btn3, &QPushButton::clicked, this, [=]{
        group->start();
    });
}

在这里插入图片描述

六、使用缓和曲线

  在 Qt 的动画系统中,缓和曲线(Easing Curve) 用于控制动画过程中属性值随时间的变化速度,也就是“动画节奏感”。这通过 QEasingCurve 类实现,可以让动画效果更自然、生动,比如:

  • 加速、减速(常见于 UI 移动)
  • 弹跳、回弹(常见于游戏 UI)
  • 弹性伸缩(拟物风格)

设置缓和曲线的方法:
每个 QPropertyAnimation 都可以通过如下方式设置缓和曲线:

QPropertyAnimation *anim = new QPropertyAnimation(widget, "pos");
anim->setDuration(1000);
anim->setStartValue(QPoint(0, 0));
anim->setEndValue(QPoint(200, 200));

// 设置缓和曲线
anim->setEasingCurve(QEasingCurve::OutBounce);

常用缓和曲线类型:
在这里插入图片描述
示例:三种不同节奏的移动动画

#include <QPushButton>
#include <QPropertyAnimation>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    QStringList labels = { "Linear", "OutBounce", "InOutBack" };

    for (int i = 0; i < 3; ++i) {
        QPushButton *btn = new QPushButton(labels[i], this);
        btn->move(20, 50 + i * 50);

        QPropertyAnimation *anim = new QPropertyAnimation(btn, "pos", this);
        anim->setDuration(1000);
        anim->setStartValue(QPoint(20, 50 + i * 50));
        anim->setEndValue(QPoint(250, 50 + i * 50));

        anim->setEasingCurve(QEasingCurve::OutBounce);
        anim->start(QAbstractAnimation::DeleteWhenStopped);
    }
}

此时运行程序会发现,它会使按钮部件就像从开始位置掉落到结束位置的皮球一样出现弹跳效果。

七、状态机框架

什么是状态机?
状态机(State Machine)是一种数学模型,用来表示对象的状态和状态之间的切换规则。在 Qt 中,状态机由以下核心元素组成:

  • QStateMachine:状态机管理器;
  • QState / QFinalState:状态;
  • QAbstractTransition:状态间的过渡;
  • QSignalTransition:基于信号的过渡;
  • QHistoryState:记住某个状态组最后进入的子状态(可用于“返回上次状态”);
  • QState::assignProperty():状态进入时自动设置对象属性(常用于动画或 UI 状态变化);

简单使用示例:
场景:点击按钮在红色和绿色之间切换

#include <QPushButton>
#include <QStateMachine>
#include <QState>
#include <QSignalTransition>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    QPushButton* pBtn = new QPushButton("Toggle Color", this);

    QStateMachine *pMachine = new QStateMachine(this);

    QState *redState = new QState();
    redState->assignProperty(pBtn, "styleSheet", "background-color: red");

    QState *greenState = new QState();
    greenState->assignProperty(pBtn, "styleSheet", "background-color: green");

    // 状态切换
    redState->addTransition(pBtn, &QPushButton::clicked, greenState);
    greenState->addTransition(pBtn, &QPushButton::clicked, redState);

    // 添加状态并设置初始状态
    pMachine->addState(redState);
    pMachine->addState(greenState);
    pMachine->setInitialState(greenState);
    pMachine->start();
}

状态机和动画结合

结合状态机和动画的关键点:

  • 利用 QState::assignProperty() 设置状态进入时的属性值;
  • 使用 QStateMachine::addDefaultAnimation() 添加动画,动画会在状态切换时自动播放;
  • 动画可作用于多种属性(位置、大小、颜色、透明度等);
  • 结合定时器和事件可以实现更复杂动画状态切换。
#include <QPushButton>
#include <QStateMachine>
#include <QState>
#include <QPropertyAnimation>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setFixedSize(800, 600);
    this->setWindowTitle("动画");

    QPushButton *pBtn = new QPushButton("Click me", this);
    pBtn->setGeometry(100, 100, 150, 50);
    pBtn->show();

    QStateMachine *pMachine = new QStateMachine(this);

    // 状态1:按钮红色,左上角
    QState *state1 = new QState();
    state1->assignProperty(pBtn, "geometry", QRect(100, 100, 150, 50));
    state1->assignProperty(pBtn, "styleSheet", "background-color: red");

    // 状态2:按钮绿色,右下角
    QState *state2 = new QState();
    state2->assignProperty(pBtn, "geometry", QRect(400, 300, 150, 100));
    state2->assignProperty(pBtn, "styleSheet", "background-color: green");

    // 状态切换
    state1->addTransition(pBtn, &QPushButton::clicked, state2);
    state2->addTransition(pBtn, &QPushButton::clicked, state1);

    pMachine->addState(state1);
    pMachine->addState(state2);
    pMachine->setInitialState(state1);

    // 添加动画,自动在状态切换时播放
    QPropertyAnimation *anim = new QPropertyAnimation(pBtn, "geometry");
    anim->setDuration(500);
    anim->setEasingCurve(QEasingCurve::InOutQuad);
    pMachine->addDefaultAnimation(anim);

    pMachine->start();
}

效果显示:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值