4.6がやってきた-Qt最新事情2010

第2回 Qt 4.6のアニメーションフレームワーク[前編]

この記事を読むのに必要な時間:およそ 5 分

はじめに

これから数回に渡って,KineticプロジェクトからQt 4.6に新しく取込まれた機能について説明します。

Kineticプロジェクトは,ダイナミックに滑らかな動きをするGUIをQtで実現しようとするプロジェクトです。公開リポジトリでは,Qt 4.7で予定されている機能を含めて,開発が継続しています。

アニメーションフレームワークとは

アニメーションフレームワークでは,Qtのオブジェクト,つまりQObject※1のプロパティを動的に変更することによって,ウィジェットやグラフィックスビューのアイテム,そしてQObjectの任意のサブクラスで,アニメーション効果を利用できるようにしています。たとえば,ウィジェットの位置と大きさを決めているgeometryプロパティを時間の経過に合わせて変更して,ボタンやスライダーがウィンドウの端から動いて現れるようにするような効果を簡潔に実装できます。

※1
QObjectのプロパティについては,以前のこの記事を参考にしてください。
Qt最新事情─QtでWebKitを使ってみよう:第3回 Qtの基本プログラミング~オブジェクトモデル

アニメーションフレームワークの関連クラス

図1 Qt 4.6のアニメーションフレームワーク関連クラス

図1 Qt 4.6のアニメーションフレームワーク関連クラス

図1は,アニメーションフレームワークに用意されているクラスの概要です。

QPropertyAnimationクラスは,Qtのプロパティを動的に変更して,アニメーションをできるようにします。複数のアニメーションをつなぎ合わせたり,並列に動作させるには,QSequentialAnimationGroupとQParallelAnimationGroupを使います。これらの3つのクラスがアニメーションでよく使われ,QPauseAnimationがQSequentialAnimationGroup内のアニメーション間に一時停止時間を入れるために使われます。

今回紹介するアニメーションプログラムのソースリストはこちらからダウンロードしてください。
examples.zip

ウィジェットのアニメーション

次の動画のように,ラベルを左から右に移動させるプログラムについて説明します。このプログラムでは,図2のように一定の速度でラベルを移動させています。

ラベル移動のアニメーション

図2動画の概要

図2 動画の概要

リスト1 ラベル移動アニメーション(その1)

 1: #include <QApplication>
 2: #include <QWidget>
 3: #include <QLabel>
 4: #include <QPushButton>
 5: #include <QPalette>
 6: #include <QLayout>
 7: #include <QPropertyAnimation>
 8: 
 9: class HarnessPrivate
10: {
11: public:
12:     HarnessPrivate() 
13:         : movingAreaSize( QSize( 360, 64 ) ), horizontalOffset( 8 ) {
14:     }
15: 
16:     QSize movingAreaSize;
17:     int horizontalOffset;
18:     QPropertyAnimation* labelAnimation;
19: };
20: 
21: class Harness : public QWidget
22: {
23:     Q_OBJECT
24:     Q_DECLARE_PRIVATE( Harness )
25: 
26: public:
27:     Harness();
28:     ~Harness();
29: 
30: private slots:
31:     void startAnimation();
32: 
33: private:
34:     HarnessPrivate* d_ptr;
35: };
36: 

動くラベルを置くためのクラスです。Animate ボタンがクリックされたならば,startAnimation()スロットを呼出して,アニメーションを開始するようにします。

37: Harness::Harness()
38:     : QWidget( 0 ), d_ptr( new HarnessPrivate )
39: {
40:     Q_D( Harness );
41: 
42:     QLabel* movableLabel;
43:     movableLabel = new QLabel( "Moving", this );
44:     movableLabel->setMargin( 4 );
45:     QPalette movableLabelPalette = movableLabel->palette();
46:     movableLabelPalette.setColor( QPalette::Window, Qt::red );
47:     movableLabel->setPalette( movableLabelPalette );
48:     movableLabel->setAutoFillBackground( true );
49:     int movableLabelY = ( d->movingAreaSize.height() - movableLabel->sizeHint().height() ) / 2;
50:     movableLabel->resize( movableLabel->sizeHint() );
51:     movableLabel->move( d->horizontalOffset, movableLabelY );
52:     

動かすラベルはレイアウト機能を使って並べずに,直に位置と大きさを指定することに注意しましょう。

53:     QPushButton* animateButton = new QPushButton( "Animate" );
54: 
55:     QHBoxLayout* buttonLayout = new QHBoxLayout;
56:     buttonLayout->addStretch();
57:     buttonLayout->addWidget( animateButton );
58: 
59:     QVBoxLayout* topLayout = new QVBoxLayout;
60:     topLayout->addSpacing( d->movingAreaSize.height() );
61:     topLayout->addLayout( buttonLayout );
62: 
63:     setFixedWidth( d->movingAreaSize.width() );
64:     setLayout( topLayout );
65: 
66:     setFixedHeight( sizeHint().height() );
67: 

動かさないボタンは,レイアウト機能を使ってきれいに並べます。ラベルが動く領域を確保するために,addSpacing()で高さが固定された空白領域が取られるように調整し,ウィンドウサイズ変更時の処理を省いているので,ウィンドウサイズを固定しています。

キャプション

68:     d->labelAnimation = new QPropertyAnimation( movableLabel, "pos", this );
69:     d->labelAnimation->setDuration( 5 * 1000 );
70:     int movableLabelStartX = d->horizontalOffset;
71:     int movableLabelEndX = width() - movableLabel->sizeHint().width() - d->horizontalOffset;
72:     d->labelAnimation->setStartValue( QPoint( movableLabelStartX, movableLabelY ) );
73:     d->labelAnimation->setEndValue( QPoint( movableLabelEndX, movableLabelY ) );
74: 

QPropertyAnimationのインスタンス生成で,第一引数にアニメーション対象のオブジェクトを指定し,第二引数にアニメーションで変化させるプロパティ名を指定します。QWidgetクラスでは,posプロパティが以下のように定義されています。

Q_PROPERTY(QPoint pos READ pos WRITE move DESIGNABLE false STORED false)

QPropertyAnimation によって,posプロパティが変更される際には,アニメーション処理の内部では,Qtのメタオブジェクトシステムの機能を用いて,文字列 "pos"からmove()メソッドが求められて呼出され,ウィジェットの位置が変更されます。

setDuration()でアニメーションの動作時間を5秒に設定し,setStartValue()とsetEndValue()でアニメーションの開始値と終了値を設定しています。

75:     connect( animateButton, SIGNAL( clicked() ), SLOT( startAnimation() ) );
76: }
77: 
78: Harness::~Harness()
79: {
80:     delete d_ptr;
81: }
82: 
83: void Harness::startAnimation()
84: {
85:     Q_D( Harness );
86:     
87:     d->labelAnimation->start();
88: }
89: 

Animateボタンをクリックすると,このstartAnimation()スロットが呼び出され,labelAnimationのstart()を呼んでアニメーションを開始し,ラベルを左から右へ移動させます。このように開始値と終了値のみを設定した場合には,これらの2値を線形補間して移動が行われます。

 90: int main( int argc, char** argv )
 91: {
 92:     QApplication app( argc, argv );
 93: 
 94:     Harness harness;
 95:     harness.show();
 96: 
 97:     return app.exec();
 98: }
 99: 
100: #include "movablelabel.moc"
101: 

著者プロフィール

杉田研治(すぎたけんじ)

1955年生まれ。東京都出身。株式会社SRAに勤務。プログラマ。

仕事のほとんどをMac OS XとKubuntu KDE 4でQtと供に過ごす。

コメント

コメントの記入