Qt之动画框架
簡(jiǎn)述
Qt動(dòng)畫(huà)框架旨在為創(chuàng)建動(dòng)畫(huà)和平滑的GUI提供了一種簡(jiǎn)單的方法。通過(guò)Qt動(dòng)畫(huà)屬性,該框架為部件和其它QObject對(duì)象的動(dòng)畫(huà)操作提供了非常大的自由性,框架也可以被用于圖形視圖框架中,動(dòng)畫(huà)框架中許多可用的概念也可以用于Qt Quick,它提供了一種聲明式的方式定義動(dòng)畫(huà)。大部分關(guān)于動(dòng)畫(huà)框架學(xué)到的知識(shí)都可以應(yīng)用于Qt Quick。
本篇,我們闡述了Qt動(dòng)畫(huà)框架的基本結(jié)構(gòu)。同時(shí),會(huì)展示最常見(jiàn)的技術(shù)示例,用于動(dòng)畫(huà)操作QObject和圖形項(xiàng)。
- 簡(jiǎn)述
- 動(dòng)畫(huà)框架結(jié)構(gòu)
- 動(dòng)畫(huà)框架類(lèi)
- Qt動(dòng)畫(huà)屬性
- 動(dòng)畫(huà)和圖形視圖框架
- 緩和曲線
- 動(dòng)畫(huà)分組
- 動(dòng)畫(huà)和狀態(tài)
- 更多參考
動(dòng)畫(huà)框架結(jié)構(gòu)
本節(jié)中,我們將宏觀了解Qt動(dòng)畫(huà)框架的體系結(jié)構(gòu),以及如何被用于Qt動(dòng)畫(huà)屬性。下圖展示了動(dòng)畫(huà)框架中最重要的類(lèi)。
動(dòng)畫(huà)框架基礎(chǔ)由基類(lèi)QAbstractAnimation以及它的兩個(gè)子類(lèi)QVariantAnimation、QAnimationGroup組成。QAbstractAnimation是所有動(dòng)畫(huà)的祖先。它包含了一些在框架中被普遍使用的基本功能,尤其是啟動(dòng)、停止和暫停動(dòng)畫(huà)功能,它也接收定時(shí)觸發(fā)通知。
Qt動(dòng)畫(huà)框架更是提供了QPropertyAnimation類(lèi),該類(lèi)繼承自QVariantAnimation,用于對(duì)Qt屬性的動(dòng)畫(huà)操作(Qt屬性系統(tǒng)是Qt元對(duì)象系統(tǒng)的一部分)。QPropertyAnimation類(lèi)使用緩和曲線算法對(duì)屬性進(jìn)行插值演化操作。因此當(dāng)你想使用動(dòng)畫(huà)改變一個(gè)值時(shí),需要聲明其為一個(gè)屬性并且使該類(lèi)繼承自QObject。這給我們提供了很大的方便性,去動(dòng)畫(huà)操作現(xiàn)有的部件和其它的QObject對(duì)象。
復(fù)雜動(dòng)畫(huà)可以通過(guò)構(gòu)建QAbstractAnimation樹(shù)形結(jié)構(gòu)來(lái)構(gòu)造。該樹(shù)主要使用QAnimationGroup,QAnimationGroup類(lèi)是一個(gè)包含其它動(dòng)畫(huà)類(lèi)的容器類(lèi);同時(shí)QAnimationGroup類(lèi)也是QAbstractAnimation類(lèi)的子類(lèi),因此一個(gè)容器可以包含其它容器。
Qt動(dòng)畫(huà)框架可以獨(dú)立使用,但是也被設(shè)計(jì)為Qt狀態(tài)機(jī)框架的一部分。狀態(tài)機(jī)框架提供一個(gè)特殊的狀態(tài)用來(lái)播放動(dòng)畫(huà)。當(dāng)狀態(tài)進(jìn)入或者退出時(shí),QState也可以改變屬性。當(dāng)這個(gè)動(dòng)畫(huà)狀態(tài)提供了一個(gè)QPropertyAnimatio時(shí),這個(gè)特殊的狀態(tài)會(huì)在這些值之間進(jìn)行篡改操作。后續(xù)我們將了解的更加仔細(xì)。
在幕后,動(dòng)畫(huà)被一個(gè)全局定時(shí)器控制著,該定時(shí)器對(duì)所有正在運(yùn)行的動(dòng)畫(huà)發(fā)送更新命令。
要了解Qt動(dòng)畫(huà)框架中各個(gè)類(lèi)的功能,請(qǐng)參考相應(yīng)的類(lèi)描述信息。
動(dòng)畫(huà)框架類(lèi)
這些類(lèi)提供了用于創(chuàng)建簡(jiǎn)單的和復(fù)雜的動(dòng)畫(huà)的框架
| QAbstractAnimation | 所有動(dòng)畫(huà)類(lèi)的基類(lèi) |
| QAnimationGroup | 動(dòng)畫(huà)容器類(lèi)的抽象基類(lèi) |
| QEasingCurve | 動(dòng)畫(huà)控制的緩和曲線類(lèi) |
| QParallelAnimationGroup | 并行動(dòng)畫(huà)容器 |
| QPauseAnimation | QSequentialAnimationGroup暫停 |
| QPropertyAnimation | Qt的動(dòng)畫(huà)屬性 |
| QSequentialAnimationGroup | 串行動(dòng)畫(huà)容器 |
| QTimeLine | 控制動(dòng)畫(huà)的時(shí)間軸類(lèi) |
| QVariantAnimation | 動(dòng)畫(huà)類(lèi)的抽象基類(lèi) |
Qt動(dòng)畫(huà)屬性
如上所述,QPropertyAnimation類(lèi)能夠修改Qt屬性值,正是該類(lèi)用于改變動(dòng)畫(huà)屬性值。事實(shí)上,它的基類(lèi)QVariantAnimation是一個(gè)抽象類(lèi),所以不能被直接使用。
選用Qt動(dòng)畫(huà)屬性的一個(gè)主要原因,是因?yàn)樗o我們很大的自由性去動(dòng)畫(huà)操作Qt API中已經(jīng)存在的類(lèi),尤其是擁有bounds、colors等屬性的QWidget類(lèi)(能被嵌入到QGraphicsView中的QWidget)。
來(lái)看一個(gè)小例子:
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秒的持續(xù)時(shí)間把button從屏幕的左上角移動(dòng)到(250, 250)點(diǎn)處。
上面的例子在開(kāi)始值與結(jié)束值之間做了線性插值。當(dāng)然,設(shè)置的值在開(kāi)始處與結(jié)束處之間的數(shù)值也是合理的,那么插值衍化就沿這些點(diǎn)進(jìn)行。
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();這個(gè)例子中,在8秒的持續(xù)時(shí)間將button移到(250, 250),然后在剩下的2秒再移回至初始位置;這些點(diǎn)之間的移動(dòng)都是通過(guò)線性插值的。
你也可以動(dòng)畫(huà)操作沒(méi)有聲明動(dòng)畫(huà)屬性的QObject對(duì)象中的值,但是唯一的條件是該值有個(gè)能進(jìn)行修改的設(shè)置函數(shù)。所以可以進(jìn)行子類(lèi)化,在該類(lèi)中包含聲明屬性的值并且有個(gè)設(shè)置函數(shù)。每個(gè)Qt屬性需要一個(gè)獲取值的訪問(wèn)函數(shù),因此如果類(lèi)本身沒(méi)提供對(duì)該值的訪問(wèn)函數(shù)的話,你自己就需要提供一個(gè)。
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem {Q_OBJECTQ_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) };如上所示的代碼例子中,我們子類(lèi)化QGraphicsRectItem類(lèi),并且定義了”geometry”屬性。即使QGraphicsRectItem沒(méi)有提供”geometry”屬性,我們也可以動(dòng)畫(huà)操作MyGraphicsRectItem的位置信息了。
動(dòng)畫(huà)和圖形視圖框架
當(dāng)你想動(dòng)畫(huà)操作QGraphicsItem時(shí),也可以使用QPropertyAnimation類(lèi)。然而,QGraphicsItem并不繼承于QObject。一個(gè)好的解決辦法是子類(lèi)化一個(gè)你需要的圖形項(xiàng),同時(shí)這個(gè)類(lèi)也繼承自QObject。通過(guò)這種方式,QPropertyAnimation類(lèi)就能適用于QGraphicsItem。下面的代碼例子展示了這是如何實(shí)現(xiàn)的。另一種可行性是只繼承于QGraphicsWidget,因?yàn)镼GraphicsWidget繼承于QObject。
class Pixmap : public QObject, public QGraphicsPixmapItem {Q_OBJECTQ_PROPERTY(QPointF pos READ pos WRITE setPos)...如上所述,我們定義了一個(gè)需要?jiǎng)赢?huà)操作的屬性值。
注意:出于元對(duì)象系統(tǒng)的要求,QObject必須是第一個(gè)繼承者。
緩和曲線
QPropertyAnimation在開(kāi)始與結(jié)束之間執(zhí)行插值操作。除了為動(dòng)畫(huà)添加更多的鍵值外,你也可以使用緩和曲線,緩和曲線控制著在0與1之間的插值速度,如果你想在沒(méi)有改變插值路徑的情況下改變動(dòng)畫(huà)速度,那么緩和曲線是很有用的。
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();這里,動(dòng)畫(huà)即沿著OutBounce曲線,該曲線樣式是到結(jié)束處會(huì)彈跳起來(lái)像個(gè)彈跳球。QEasingCurve類(lèi)有大量供選擇的曲線,它們被定義成QEasingCurve::Type枚舉。如果你需要另外的曲線樣式,也可以自己實(shí)現(xiàn)一個(gè),然后用QEasingCurve注冊(cè)它既可。
動(dòng)畫(huà)分組
一個(gè)應(yīng)用程序常常包含多個(gè)動(dòng)畫(huà)。例如,你或許希望同時(shí)移動(dòng)不止一個(gè)圖形項(xiàng)或者一個(gè)接一個(gè)的順序移動(dòng)它們。
QAnimationGroup(QSequentialAnimationGroup和QParallelAnimationGroup)的子類(lèi)是動(dòng)畫(huà)容器類(lèi),因此多個(gè)動(dòng)畫(huà)可以被串行或者并行執(zhí)行。QAnimationGroup類(lèi)就是一個(gè)例子,其不操作動(dòng)畫(huà)屬性,但是它能周期性的獲得定時(shí)通知,這使得它能把定時(shí)通知應(yīng)用于動(dòng)畫(huà)中,從而進(jìn)行控制。
下面我們來(lái)看看使用QSequentialAnimationGroup和QParallelAnimationGroup的例子:
QPushButton *bonnie = new QPushButton("Bonnie"); bonnie->show();QPushButton *clyde = new QPushButton("Clyde"); clyde->show();// 動(dòng)畫(huà)一 QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");// 動(dòng)畫(huà)二 QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");QParallelAnimationGroup *group = new QParallelAnimationGroup; group->addAnimation(anim1); group->addAnimation(anim2);group->start();并行容器內(nèi)的動(dòng)畫(huà)是同時(shí)進(jìn)行的,調(diào)用它的start()函數(shù)即開(kāi)始操作它所管理的所有動(dòng)畫(huà)。
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();毫無(wú)疑問(wèn)你已經(jīng)猜到了,QSequentialAnimationGroup串行的操作它所管理的動(dòng)畫(huà)。
因?yàn)閯?dòng)畫(huà)容器類(lèi)也是動(dòng)畫(huà),所以你可以將其加入到其它動(dòng)畫(huà)容器里;用這種方式,就可以建造一個(gè)動(dòng)畫(huà)樹(shù)結(jié)構(gòu),該結(jié)構(gòu)指定了動(dòng)畫(huà)彼此之間運(yùn)行的關(guān)系。
動(dòng)畫(huà)和狀態(tài)
當(dāng)使用狀態(tài)機(jī)時(shí),我們可以使用QSignalTransition或QEventTransition類(lèi)將一個(gè)或者多個(gè)動(dòng)畫(huà)與狀態(tài)之間的切換中進(jìn)行關(guān)聯(lián)。這些類(lèi)繼承于QAbstractTransition,QAbstractTransition類(lèi)提供了便利的函數(shù)addAnimation(),該函數(shù)在狀態(tài)切換發(fā)生的情況下能觸發(fā)一個(gè)或多個(gè)被附加的動(dòng)畫(huà)。
我們也可以和狀態(tài)進(jìn)行屬性關(guān)聯(lián),而不是自己設(shè)置開(kāi)始和結(jié)束值,下面就是一段完整的動(dòng)畫(huà)操作QPushButton位置的代碼例子:
QPushButton *button = new QPushButton("Animated Button"); button->show();QStateMachine *machine = new QStateMachine;QState *state1 = new QState(machine); state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30)); machine->setInitialState(state1);QState *state2 = new QState(machine); state2->assignProperty(button, "geometry", QRect(250, 250, 100, 30));QSignalTransition *transition1 = state1->addTransition(button,SIGNAL(clicked()), state2); transition1->addAnimation(new QPropertyAnimation(button, "geometry"));QSignalTransition *transition2 = state2->addTransition(button,SIGNAL(clicked()), state1); transition2->addAnimation(new QPropertyAnimation(button, "geometry"));machine->start();有關(guān)如何使用動(dòng)畫(huà)狀態(tài)機(jī)框架更全面的示例,請(qǐng)參見(jiàn)狀態(tài)示例(位于examples/animation/states目錄)。
更多參考
- The Animation Framework(助手)
- Qt之QPropertyAnimation
- Qt之QSequentialAnimationGroup
- Qt之QParallelAnimationGroup
- Qt之QPauseAnimation
- Qt之窗口動(dòng)畫(huà)(下墜、抖動(dòng)、透明度)
轉(zhuǎn)載于:https://www.cnblogs.com/itrena/p/5938274.html
總結(jié)
- 上一篇: mysql的partition分区
- 下一篇: Win7常规快捷键