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

第5回 ステートマシーンフレームワークの詳細

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

前回はステートマシーンフレームワークの経緯を説明し,詳しいことは省いて「アニメーションフレームワーク」の説明の最後の「パラレルアニメーションによるアニメーションの並行実行」のサンプルプログラムにアニメーションフレームワークを適用した例を示しました。今回は,ステートマシーンフレームワークの個々の機能を少し詳しく見てみましょう。

ステートマシンフレームワークの使用手順

ステートマシンフレームワークの基本的な使用手順は次のようになります。

①状態遷移機械の生成

QStateMachineのインスタンスを生成します。

②状態の生成

QStateのインスタンスが状態を表し,コンストラクタにはQStateMachineまたはQStateのインスタンスを指定します。通常の状態では,QStateMachineを渡してQState のインスタンスを生成します。複合状態や並列状態を生成する場合には,QState のインスタンスを渡します。

③遷移の生成

オブジェクトのシグナル送信によって引き起される遷移の場合には,QSignalTransitionのインスタンスを生成し,マウスとキーによる場合には,QMouseEventTransitionやQKeyEventTransitionのインスタンスを生成して,遷移を生成し,QState::addTransition() で,状態に遷移を設定します。

以下のような,簡単にトランジションを設定できるメソッドも用意されています。

QState::addTransition( QObject* sender, const char* signal, QAbstractState* target )

QAbstractTransition::addAnimation()で必要に応じてアニメーションを付加します。

④初期状態の設定

QStateMachine::setInitialState()で,初期状態となるQStateのインスタンスを設定します。複合状態や並列状態の場合には,入れ子になった各状態に対して,QState::setInitialState()で初期状態を設定します。

⑤状態遷移機械の起動

QStateMachineのインスタンスに対してstart() を呼び出します。

基本的なステートマシンフレームワークの適用例

ステートマシンフレームワークのサンプルプログラムがQtに付属しています。まず,基本的なTwo-way Button Exampleで,前述のステートマシンフレームワークの使用手順を確認しましょう。

このサンプルプログラムを動かすと,図1のようにクリックするたびにボタンのテキストがOffとOnに切り替わります。

図1 “Two-way Button Example⁠の動作

図1 “Two-way Button Example”の動作

状態遷移図は図2のようになります。前回のサンプルプログラムの状態遷移図と本質的には同じです。

図2 “Two-way Button Example⁠の状態遷移

図2 “Two-way Button Example”の状態遷移

サンプルプログラムを見ていきましょう。

リスト1 Two-way Button Example

 1: #include <QtGui>
 2: 
 3: int main(int argc, char **argv)
 4: {
 5:     QApplication app(argc, argv);
 6:     QPushButton button;
 7:     QStateMachine machine;

「状態遷移機械の生成」です。

 9:     QState *off = new QState();
10:     off->assignProperty(&button, "text", "Off");
11:     off->setObjectName("off");
12: 
13:     QState *on = new QState();
14:     on>setObjectName("on");
15:     on->assignProperty(&button, "text", "On");

「状態の生成」です。onとoffの2つの状態を用意し,各状態でのプロパティを設定しています。このような簡単なものでは不要ですが,オブジェクト名をsetObjectName()で付けるようにしておくと,複雑な状態遷移を使ったときにデバッグがしやすくなります。

17:     off->addTransition(&button, SIGNAL(clicked()), on);
18:     on->addTransition(&button, SIGNAL(clicked()), off);

状態に,addTransition()で遷移を設定しています。簡易メソッドを使っているので,明示的にQSignalTransitionのインスタンスを生成していませんが,内部で生成されます。QStateには以下の3つのaddTransition()メソッドが用意されています。

void addTransition(QAbstractTransition* transition)

QSignalTransition,QMouseEventTransitionやQKeyEventTransitionのインスタンスを生成してから設定します。リスト1の17~18行は,以下のように書き換えられます。

QSignalTransition *fromOfftoOnTransition = new QSignalTransition(&button, SIGNAL(clicked()), off);
fromOfftoOnTransition->setTargetState(on);
QSignalTransition *fromOntoOffTransition = new QSignalTransition(&button, SIGNAL(clicked()), on);
fromOntoOffTransition->setTargetState(off);

QSignalTransitionのインスタンスの所有者は,offまたはonのQStateインスタンスになることに注意しましょう。

QSignalTransition *addTransition(QObject *sender, const char *signal, QAbstractState *target)

このサンプルプログラムで使われているメソッドです。signalにはQObject::connect()と同様に,マクロSIGNAL()によって正規化したシグナルのシグネチャ文字列を渡します。

QAbstractTransition *addTransition(QAbstractState *target)

無条件遷移で,遷移のためのトリガーはなく,元状態からtargetに指定した状態にすぐに遷移します。

20:     machine.addState(off);
21:     machine.addState(on);

「状態の生成」の変形で20~21を削除し,9行目と13行目を以下のようにしても同じ状態遷移機械となり,同じ動作をします。

 9:    QState *off = new QState(&machine);
        
13:   QState *on = new QState(&machine);
23:     machine.setInitialState(off);

「初期状態の設定」です。起動直後の状態がoffになります。

24:     machine.start();

「状態遷移機械の起動」です。状態遷移機械がイベントループで開始されるようにスケジューリングされます。

26:     button.resize(100, 50);
27:     button.show();
28:     return app.exec();
29: }

著者プロフィール

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

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

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

コメント

コメントの記入