動態創建狀態機和編譯狀態機兩者行為方式相同,擁有相同特性、狀態、數據模型等。它們僅實例化方式有所不同。要從 SCXML 文件以 C++ 動態創建一個,可以使用:
auto *stateMachine = QScxmlStateMachine::fromFile("MyStatemachine.scxml");
或,以 QML:
import QtScxml 5.8 Item { property StateMachine stateMachine: scxmlLoader.stateMachine StateMachineLoader { id: scxmlLoader source: "statemachine.scxml" } }
編譯狀態機的實例化方式如同任何 C++ 對象:
auto *stateMachine = new MyStatemachine;
或:
MyStatemachine stateMachine;
要在 QML 中使用編譯狀態機,可以將其注冊成 QML 類型:
qmlRegisterType<MyStateMachine>("MyStateMachine", 1, 0, "MyStateMachine");
然後,可以在 QML 中實例化它,像這樣:
import MyStateMachine 1.0 MyStateMachine { id: stateMachine }
要編譯狀態機,必須將以下行添加到 .pro 文件:
QT += scxml STATECHARTS = MyStatemachine.scxml
This will tell qmake to run qscxmlc which generates MyStatemachine.h and MyStatemachine.cpp, and adds them to HEADERS and SOURCES variables. By default, the generated files are saved in the build directory. The QSCXMLC_DIR variable can be set to specify another directory. The QSCXMLC_NAMESPACE variable can be set to put the state machine code into a C++ namespace.
After instantiating a state machine, you can connect to any state's active property as follows. For example, if the state machine for a traffic light has a state indicating that the light is red (which has the convenient id "red" in the scxml file), you can write:
stateMachine->connectToState("red", [](bool active) { qDebug() << (active ? "entered" : "exited") << "the red state";
And in QML:
Light { id: greenLight color: "green" visible: stateMachine.green }
If you want to be notified when a state machine sends out an event, you can connect to the corresponding signal. For example, for a media player state machine which indicates that playback has stopped by sending an event, you can write:
stateMachine->connectToEvent("playbackStopped", [](const QScxmlEvent &){ qDebug() << "Stopped!"; });
And in QML:
import QtScxml 5.8 EventConnection { stateMachine: stateMachine events: ["playbackStopped"] onOccurred: console.log("Stopped!") }
Sending events to a state machine is equally simple:
stateMachine->submitEvent("tap", QVariantMap({ { "artist", "Fatboy Slim" }, { "title", "The Rockafeller Skank" } });
This will generate a "tap" event with the map contents available in _event.data inside the state machine. In QML:
stateMachine.submitEvent("tap", { "artist": "Fatboy Slim" "title": "The Rockafeller Skank" })
注意:
狀態機需要
QEventLoop
to work correctly. The event loop is used to implement the
delay
attribute for events and to schedule the processing of a state machine when events are received from nested (or parent) state machines. A QML application or a widget application will always have an event loop running, so nothing extra is needed. For other applications,
QApplication::run
will have to be called to start the event loop processing.