qt的動畫和狀態機
一 簡介
動畫框架用於建立的GUI ,它可以為GUI快速轉換為柔和的畫面及新增原色。可以在QT提供的控制元件,QObject派生的類控制元件等元素上使用動畫效果。
狀態機 即有限狀態機,用於定義狀態之間的移動,例如,開關的行為動作可以分為ON/OFF兩種,根據其行為變為ON/OFF。如果使用狀態機,則可以簡單快捷地實現對動畫的行為組合。
動畫框架除了提供基於C++的GUI建立框架外,還提供可以再QT Quick中使用的框架。
QAbstractAnimation | 所有動畫類的基類 |
QAnimationGroup | 動畫組的抽象基類 |
QEasingCurve | 控制動畫的Easing |
QParallerAnimationGroup | 並行處理多個動畫 |
QPauseAnimation | 暫停QSequentialAnimationGroup |
QSequentialAnimationGroup | 序列SequentialAnimation動畫組 |
QVariantAnimation | 動畫的抽象基類 |
QTimeLIne | 控制動畫的時間線 |
二 動畫框架
本節中,我們將巨集觀瞭解Qt動畫框架的體系結構,以及如何被用於Qt動畫屬性。下圖展示了動畫框架中最重要的類。
動畫框架基礎由基類QAbstractAnimation以及它的兩個子類QVariantAnimation、QAnimationGroup組成。QAbstractAnimation是所有動畫的祖先。它包含了一些在框架中被普遍使用的基本功能,尤其是啟動、停止和暫停動畫功能,它也接收定時觸發通知。
Qt動畫框架更是提供了QPropertyAnimation類,該類繼承自QVariantAnimation,用於對Qt屬性的動畫操作(Qt屬性系統是Qt元物件系統的一部分)。QPropertyAnimation類使用緩和曲線演算法對屬性進行插值演化操作。因此當你想使用動畫改變一個值時,需要宣告其為一個屬性並且使該類繼承自QObject。這給我們提供了很大的方便性,去動畫操作現有的部件和其它的QObject物件。
複雜動畫可以通過構建QAbstractAnimation樹形結構來構造。該樹主要使用QAnimationGroup,QAnimationGroup類是一個包含其它動畫類的容器類;同時QAnimationGroup類也是QAbstractAnimation類的子類,因此一個容器可以包含其它容器。
Qt動畫框架可以獨立使用,但是也被設計為Qt狀態機框架的一部分。狀態機框架提供一個特殊的狀態用來播放動畫。當狀態進入或者退出時,QState也可以改變屬性。當這個動畫狀態提供了一個QPropertyAnimatio時,這個特殊的狀態會在這些值之間進行篡改操作。後續我們將瞭解的更加仔細。
在幕後,動畫被一個全域性定時器控制著,該定時器對所有正在執行的動畫傳送更新命令。
要了解Qt動畫框架中各個類的功能,請參考相應的類描述資訊。
三 動畫舉例
在.pro
# Made By ldp
SOURCES += \
main.cpp \
Widget.cpp
HEADERS += \
Widget.h
TRANSLATIONS += zh_CN.ts //用於載入資源管理檔案翻譯
RESOURCES += \
Resource.qrc
QT += widgets
.qm檔案是QT工程用於進行自定義中英文翻譯的原始檔,可見當年本地化、UNICODE不甚流行的時候,咱們的先烈們還想出了各種各樣的本地化招式。不多扯了,基於google的結果分析,.qm檔案是釋出出來給QT工程的translate類進行讀取的原始檔,這個檔案對於我們人是看不懂的;故而有了.ts檔案(xml格式),xml的編輯就相當方便了
TS檔案的生成:
lupdate.exe -verbose -pro xx.pro -ts xx.ts
TS檔案其格式是XML的,可以通過編譯器進行編輯或是linguist語言專家工具進行編輯翻譯。
它們的聯絡:
TS檔案———–》QM檔案(通過QT中的lrelease工具進行轉換);
轉換方法:
lrelease.exe -verbose xx.ts -qm xx.qm
或是圖形介面釋出,使用linguist,通過圖形介面去生成qm檔案
#include <QApplication>
#include <QTranslator>
#include "Widget.h"
#include "qgraphicsitem.h"
int main( int argc, char** argv )
{
QApplication app( argc, argv );
QTranslator trans; //文字輸出有國際支援,翻譯
trans.load( ":/zh_CN.qm" );//載入生成圖形管理檔案
app.installTranslator( &trans );
Widget w;
w.show( );
//設定全域性字型的大小
QFont font = app.font();
font.setPointSize(5);
app.setFont(font);
//QGraphicsItem iItem;
//iItem.setFlag(QGraphicsItem::ItemStacksBehindParent);
return app.exec( );
}
#include <QState>
#include <QSignalTransition>
#include "Widget.h"
#include "qdebug.h"
#include "qtimeline.h"
/*---------------------------------------------------------------------------*/
Widget::Widget( void ): QWidget( 0 )
{
// 設定視窗的成員
resize( 640, 360 );
setWindowTitle( tr( "Qt_EasyAnimation2" ) );
m_pButton = new QPushButton( tr( "Please Help" ), this );//tr translate 中文
// int textWidth = fontMetrics( ).width( m_pButton->text( ) );
// int textHeight = fontMetrics( ).height( );
m_pButton->setGeometry(0,0,100,30);
m_pButtonOne = new QPushButton( tr( "China" ), this );
m_pButtonOne->setGeometry(0,40,100,30);//開始大小
// 設定動畫和有限狀態機
m_pMachine = new QStateMachine( this );
QState* pState1 = new QState( m_pMachine );
QState* pState2 = new QState( m_pMachine );
pState1->assignProperty( m_pButton, "geometry",
QRect( 0, 0, 50, 15 ) );//ctl size of action for controling
pState2->assignProperty( m_pButton, "geometry",
QRect( width( ) -100,
height( ) -30,
100, 30 ) );// 狀態之間的變換可以實現大小也變化
QSignalTransition* transition1 = pState1->addTransition(
m_pButton, SIGNAL( clicked( ) ), pState2 );//
QSignalTransition* transition2 = pState2->addTransition(
m_pButton, SIGNAL( clicked( ) ), pState1 );
QPropertyAnimation* pAnimation =
new QPropertyAnimation( m_pButton, "geometry" );//set proprety
pAnimation->setDuration( 5000 );//set time of animation
transition1->addAnimation( pAnimation );
transition2->addAnimation( pAnimation );//to property state
QEasingCurve easing (QEasingCurve::InOutCubic); //實現動畫運動的方式
for(qreal t = 0.0;t <1.0;t += 0.1)
{
qDebug()<<"effective progress" << t<<"is"
<<easing.valueForProgress(t); //mapping back time
}
pAnimation->setEasingCurve(QEasingCurve::InCubic);
m_pMachine->setInitialState( pState1 );// 設定初始的狀態
m_pMachine->start();
QTimeLine *timeline = new QTimeLine(5000); //動畫的時間控制線
timeline->setFrameRange(0,5);//5 幀
timeline->setDirection(QTimeLine::Forward);//增加動畫當前進行時間時,返回為0
connect(timeline,SIGNAL(frameChanged(int)),this,SLOT(frameSlot(int)));//每一幀的變化將發出一個訊號
timeline->start();
connect(timeline,SIGNAL(finished()),this,SLOT(animationFinish()));
}
//
void Widget::frameSlot(int frame)
{
// 執行了四次
qDebug()<<"frame is"<<frame<<endl;
if (frame == 5)
{
qDebug()<<"time over later animationFinish";
}
}
// 將動畫線完成時會發出一個finish訊號
void Widget::animationFinish()
{
QPropertyAnimation *animation;
animation = new QPropertyAnimation(m_pButtonOne,"geometry",this);
animation->setDuration(3000);
animation->setStartValue(QRect(0,40,100,30));
animation->setEndValue(QRect(0,345,50,15));
animation->start();
}