Qt動畫框架由本人終於翻譯完畢,這里的每個字母、每個漢字、每張圖片都是有本人一個一個敲打出來的,現把它共享出來。
Qt動畫框架是Kinetic項目的一部分,主要目的是提供一種簡單的方法用於創建動畫的和平滑的GUI。通過Qt動畫屬性,Qt動畫框架為部件和其他QObject對象的動畫操作提供了非常大的自由性。Qt動畫框架也能用於圖形視圖框架中。
在這片文章中,我們闡述了Qt動畫框架的基本結構。我們也提供了一些通用性編碼技術方面的例子用於動畫操作QObject和圖形項。
1、Qt動畫框架結構
在這節中,我們宏觀了解下Qt動畫框架結構以及其怎么被使用於Qt動畫屬性。下圖展示了Qt動畫框架中的一些重要類。
Qt動畫框架基石由QAbstractAnimation以及它的兩個子類QVariantAnimation和QAnimationGroup組成。QAbstractAnimation類是所有動畫類的祖先。它包含了一些在框架中被普遍使用的基本功能;尤其是啟動、停止和暫停動畫功能。它也接收定時觸發通知。
Qt動畫框架更是提供了QPropertyAnimation類,該類繼承於QVariantAnimation類,用於對Qt屬性的動畫操作(Qt屬性系統是Qt元對象系統的一部分)。QPropertyAnimation類使用緩和曲線算法對屬性進行插值演化操作。因此當你想動畫改變一個值時,你就聲明該值為一個屬性值並且使該類為成為一個QObject對象。這給我們提供了很大的方便性去動畫操作現有的部件和其他的QObject對象。
復雜動畫可以通過構建QAbstractAnimation樹形結構來構造。該樹主要使用QAnimationGroup,QAnimationGroup類是一個包含其他動畫類的容器類;同時QAnimationGroup類也是QAbstractAnimation類的子類,因此一個容器可以包含其他容器。
Qt動畫框架既是獨立的一部分,也是Qt狀態機框架的一部分。Qt狀態機框架提供一個狀態用來行使動畫。當QState進入或者退出時可以改變屬性,當這個動畫狀態提供了一個QPropertyAnimatio時,則動畫狀態即在這些值之間進行插值衍化操作。后續我們將了解的更加仔細。
在幕后,動畫被一個全局定時器控制着,該定時器對所有動畫對象發送更新命名。
為了知道Qt動畫框架中各個類的功能角色,請參考相應的類描述信息。
2、Qt動畫框架類
這些類提供了框架骨架用於創建簡單的和復雜的動畫功能
QAbstractAnimation |
所有動畫類的基類 |
QAnimationGroup |
動畫容器類的抽象基類 |
QEasingCurve |
動畫控制的緩和曲線類 |
QParallelAnimationGroup |
並行動畫容器 |
QPauseAnimation |
QSequentialAnimationGroup對象暫停延遲 |
QPropertyAnimation |
Qt動畫屬性操作 |
QSequentialAnimationGroup |
串行動畫容器 |
QTimeLine |
動畫控制的時間片類 |
QVariantAnimation |
動畫類的抽象基類 |
3、Qt動畫屬性
正如上述所提到的,QPropertyAnimation類能夠修改Qt屬性值。正是該類用於改變動畫屬性值;事實上,它的基類QVariantAnimation是一個抽象類,所以QVariantAnimation不能被直接使用。
我們選用Qt動畫屬性的一個主要原因是由於它給了我們很大的自由性去動畫操作已經存在的類,尤其是擁有bounds、colors等屬性的QWidget類(QWidget能被嵌入到QGraphicsView類)。我們看看一個小例子:
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秒的期限把button從屏幕的左上角移動到(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秒的期限將button移到(250,250),然后在剩下的2秒時間移回至初始的位置;這些點之間的移動都是通過線性插值的。
你也可以動畫操作沒有申明動畫屬性的QObject對象中的值,但是唯一的條件是該值有個能進行修改的設置函數。所以你可以進行子類化,在該類中包含聲明屬性的值並且有個設置函數。每個Qt屬性需要一個獲取值的訪問函數,因此如果類本身沒提供對該值的訪問函數的話,你自己就需要提供一個。
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
};
如上所示的代碼例子中,我們子類化QGraphicsRectItem類並且定義了”geometry”屬性。現在我們即可動畫操作MyGraphicsRectItem的位置信息了,即使QGraphicsRectItem沒有提供”geometry”屬性。
4、動畫和圖形視圖框架
當你想動畫操作QGraphicsItem時,你也是使用QPropertyAnimation類。然而,QGraphicsItem並不繼承於QObject。一個好的解決辦法是子類化一個你需要的圖形項,同時子類也繼承於QObject。使用這種方法,QPropertyAnimation類就能使用於QGraphicsItem中。下面的代碼例子展示了這種解決辦法。另一種可行性是只繼承於QGraphicsWidget,因為QGraphicsWidget繼承於QObject。
class Pixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
...
就如上述所描述的那樣,我們定義了一個我們需要動畫操作的屬性值。
注意:QObject必須是第一個繼承者,因為出於元對象系統的要求。
5、緩和曲線
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();
上述代碼中,動畫即沿着OutBounce曲線,該曲線樣式是到結束處會彈跳起來像個彈跳球。QEasingCurve類有大量的供你選擇的曲線,它們被定義成QEasingCurve::Type枚舉。如果你需要另外的曲線樣式,你也可以自己實現一個,然后用QEasingCurve注冊它既可。
6、動畫分組
一個應用程序常常包含不止一個動畫。例如,你或許希望同時移動不止一個圖形項或者一個接着一個的順序移動它們。
QAnimationGroup (QSequentialAnimationGroup和QParallelAnimationGroup)的子類是動畫容器類,因此多個動畫可以被串行或者並行。QAnimationGroup類就是一個例子,其不操作動畫屬性,但是它能周期性的獲得定時通知,這使得它能把定時通知應用於動畫中,從而進行控制。
下面我們來看看使用QSequentialAnimationGroup和QParallelAnimationGroup的例子:
QPushButton *bonnie = new QPushButton("Bonnie");
bonnie->show();
QPushButton *clyde = new QPushButton("Clyde");
clyde->show();
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
// Set up anim1
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
// Set up anim2
QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);
group->start();
並行容器內的動畫是同時進行的,調用它的start()函數即開始操作它所管理的所有動畫。
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串行的操作它所管理的動畫。
因為動畫容器類也是屬於動畫,所以你可以把加入到其他動畫容器里;用這種方法你就可以建造一個動畫樹結構,該結構指定了動畫之間的相互時間關系。
7、動畫和狀態
當使用Qt狀態機時,我們可以使用QSignalTransition或QEventTransition類將一個或者多個動畫與狀態之間的切換中進行關聯。這些類繼承於QAbstractTransition,QAbstractTransition類提供了方便的函數addAnimation(),該函數在狀態切換發生的情況下能觸發一個或多個被附加的動畫。
我們也可以和狀態進行屬性關聯,而不是自己設置開始和結束值,下面就是一段完整的動畫操作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();
word文檔(請使用word2007或以上版本打卡)下載地址:http://files.cnblogs.com/appsucc/Qt_Animation_Framework.rar