ピンポン・ステーツ

「ピンポン・ステーツ」の例では、Qt State Machine フレームワークにおいて、並列ステートとカスタムイベントおよび遷移を組み合わせて使用する方法を紹介しています。

この例では、2つの状態がステートマシンへのイベントの投稿を通じて通信するステートチャートを実装しています。ステートチャートは以下のようになります:

2つの並行する状態:ピンガーはエントリ時にpingを投稿し、pongに応答する。ポンガーはpingに応答してpongを投稿する。

「pinger 」と「ponger 」の状態は並列状態です。つまり、これらは同時に移行され、互いに独立して遷移を行います。

pinger 状態は、進入時に最初のping イベントを投稿します。これに対し、ponger 状態はpong イベントを投稿して応答します。これにより、pinger 状態が新たなping イベントを投稿することになり、この連鎖が繰り返されます。

class PingEvent : public QEvent
{
public:
    PingEvent() : QEvent(PingEventType) { }
};

class PongEvent : public QEvent
{
public:
    PongEvent() : QEvent(PongEventType) { }
};

2つのカスタムイベント、PingEvent とPongEvent が定義されています。

classPinger :publicQState
{
public:
    explicitPinger(QState*parent) : QState(parent) { }

protected:
    voidonEntry(QEvent*) override
    {
        machine()->postEvent(newPingEvent);
        qInfo() << "ping?";
    }
};

Pinger クラスは、その状態に入った際にステートマシンに `PingEvent ` を送信する状態を定義しています。

classPingTransition :publicQAbstractTransition
{
public:
    PingTransition() {}

protected:
    booleventTest(QEvent*e) override {return e->type()==PingEventType; }

    voidonTransition(QEvent*) override
    {
        machine()->postDelayedEvent(newPongEvent, 500);
        qInfo() << "pong!";
    }
};

PingTransition クラスは、PingEvent 型のイベントによってトリガーされる遷移を定義し、遷移がトリガーされた際に(500ミリ秒の遅延をもって)PongEvent をステートマシンに送信します。

classPongTransition :publicQAbstractTransition
{
public:
    PongTransition() {}

protected:
    booleventTest(QEvent*e) override {return(e->type()==PingEventType); }

    voidonTransition(QEvent*) override
    {
        machine()->postDelayedEvent(newPingEvent, 500);
        qInfo() << "ping?";
    }
};

PongTransition クラスは、PongEvent 型のイベントによってトリガーされる遷移を定義しており、遷移がトリガーされた際に、PingEvent (500ミリ秒の遅延付き)をステートマシンに送信します。

int main(int argc, char **argv)
{
    QCoreApplication app(argc, argv);

    QStateMachine machine;
    auto group = new QState(QState::ParallelStates);
    group->setObjectName("group");

main() 関数は、まずステートマシンと並列ステートグループを作成することから始まります。

    auto pinger = new Pinger(group);
    pinger->setObjectName("pinger");
    pinger->addTransition(new PongTransition);

    auto ponger = new QState(group);
    ponger->setObjectName("ponger");
    ponger->addTransition(new PingTransition);

次に、pinger およびponger という状態が、並列状態グループを親状態として作成されます。 なお、遷移にはターゲットが設定されていません。このような遷移がトリガーされた場合、ソース状態から退出したり再進入したりすることはなく、遷移の onTransition() 関数が呼び出されるだけで、ステートマシンの構成は変更されません。これは、このケースにおいてまさに私たちが求めている動作です。

    machine.addState(group);
    machine.setInitialState(group);
    machine.start();

    return app.exec();
}

最後に、グループがステートマシンに追加され、マシンが起動され、アプリケーションのイベントループに入ります。

サンプルプロジェクト @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.