動畫架構旨在為建立動畫和流暢的 GUI 提供一種簡單的方法。通過動畫 Qt 屬性,該架構為動畫小部件和其他 QObject 提供了很大的自由。該架構還可以與圖形視圖架構一起使用。動畫架構中可用的許多概念在 Qt Quick 中也可用,它提供了一種定義動畫的聲明方式。有關動畫架構的大部分知識都可以應用于 Qt Quick。
一、動畫架構
下圖顯示了動畫架構中最重要的類。

QAbstractAnimation 是所有動畫的祖先。它代表架構中所有動畫通用的基本屬性,尤其是啟動、停止和暫停動畫的能力。它還接收時間更改通知。
動畫架構進一步提供了 QPropertyAnimation 類,該類繼承 QVariantAnimation 并執行 Qt 屬性的動畫(屬性是 Qt 元對象系統的一部分)。該類使用緩動曲線對屬性執行插值。是以當想為一個值設定動畫時,可以将它聲明為一個屬性并使該類成為 QObject 的子類,這使得可以自由地為現有的小部件和其他 QObject 設定動畫。
可以通過建構 QAbstractAnimations 的樹結構來建構複雜的動畫。該樹是通過使用 QAnimationGroups 建構的,QAnimationGroups 用作其他動畫的容器。注意,組是 QAbstractAnimation 的子類,是以組本身可以包含其他組。
在幕後,動畫由全局計時器控制,該計時器向所有正在播放的動畫發送更新。
二、類清單
- QAbstractAnimation
- QAnimationGroup
- QEasingCurve
- QParallelAnimationGroup
- QPauseAnimation
- QPropertyAnimation
- QSequentialAnimationGroup
- QTimeLine
- QVariantAnimation
三、Qt 屬性動畫
QPropertyAnimation 類可以對 Qt 屬性進行插值。
選擇為 Qt 屬性設定動畫的一個主要原因是它可以自由地為 Qt API 中的現有類設定動畫。看一個小例子:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button, "geometry");
animation.setDuration(10000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));
animation.start();
此代碼将在 10 秒(10000 毫秒)内将按鈕從螢幕左上角移動到位置 (250, 250)。
上面的示例将在開始值和結束值之間進行線性插值。也可以設定位于開始值和結束值之間的值。 然後插值将通過這些點:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button, "geometry");
animation.setDuration(10000);
animation.setKeyValueAt(0, QRect(0, 0, 100, 30));
animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30));
animation.setKeyValueAt(1, QRect(0, 0, 100, 30));
animation.start();
動畫将在 8 秒内将按鈕帶到 (250, 250),然後在剩餘的 2 秒内将其移回其原始位置。運動将在這些點之間線性插值。
還可以對未聲明為 Qt 屬性的 QObject 的值進行動畫處理。唯一的要求是這個屬性有一個 setter。 注意,每個 Qt 屬性都需要一個 getter。如:
Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
Qt 屬性系統見:Qt屬性系統。
四、動畫和圖形視圖架構
當想要為 QGraphicsItems 設定動畫時,還可以使用 QPropertyAnimation。但是,QGraphicsItem 不繼承 QObject,需要改用 QGraphicsObject 或 QGraphicsWidget 或同時繼承 QObject 和QGraphicsItem。
class Pixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
...
注意,QObject 必須是第一個繼承的類,因為元對象系統需要這樣做。
五、緩和曲線
QPropertyAnimation 在開始和結束屬性值之間執行插值。除了向動畫添加更多關鍵值之外,還可以使用緩和曲線。緩和曲線描述了一個函數,該函數控制 0 和 1 之間的插值速度應該如何,如果想在不更改插值路徑的情況下控制動畫的速度,則該曲線很有用。
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button, "geometry");
animation.setDuration(3000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));
animation.setEasingCurve(QEasingCurve::OutBounce);
animation.start();
在這裡,動畫将遵循一條曲線,使其像球一樣反彈,就像從開始位置到結束位置一樣。QEasingCurve 有大量曲線供您選擇。這些由 QEasingCurve::Type 枚舉定義。如果需要自定義曲線,也可以自己實作一個,并用QEasingCurve注冊。
六、将動畫放在一起
應用程式通常會包含多個動畫。例如,可能希望同時移動多個圖形項目或依次移動多個圖形項。
QAnimationGroup 的子類是其他動畫的容器:
- QParallelAnimationGroup(并行組)
- QSequentialAnimationGroup (串行組)
QParallelAnimationGroup 示例:
QPushButton *bonnie = new QPushButton("Bonnie");
bonnie->show();
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
QPushButton *clyde = new QPushButton("Clyde");
clyde->show();
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);
group->start();
一個并行組同時播放多個動畫。調用它的 start() 函數将啟動它管理的所有動畫。
QSequentialAnimationGroup 示例:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation anim1(&button, "geometry");
anim1.setDuration(3000);
anim1.setStartValue(QRect(0, 0, 100, 30));
anim1.setEndValue(QRect(500, 500, 100, 30));
QPropertyAnimation anim2(&button, "geometry");
anim2.setDuration(3000);
anim2.setStartValue(QRect(500, 500, 100, 30));
anim2.setEndValue(QRect(1000, 500, 100, 30));
QSequentialAnimationGroup group;
group.addAnimation(&anim1);
group.addAnimation(&anim2);
group.start();
QSequentialAnimationGroup 按順序播放動畫。 它在上一個動畫完成後開始清單中的下一個動畫。
由于動畫組本身就是一個動畫,是以可以将其添加到另一個組中。通過這種方式,可以建構動畫的樹結構,指定動畫的播放時間。