IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Instantiating State Machines

Instantiating dynamically created and compiled state machines in C++ and QML.

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Instantiating State Machines

Both the dynamically created and the compiled state machines behave in the same way, have the same properties, states, data model, and so on. They only differ in the way they are instantiated. To dynamically create one in C++ from an SCXML file, you can use:

 
Sélectionnez
auto *stateMachine = QScxmlStateMachine::fromFile("MyStatemachine.scxml");

Or, in QML:

 
Sélectionnez
import QtScxml

Item {
    property StateMachine stateMachine: scxmlLoader.stateMachine

    StateMachineLoader {
        id: scxmlLoader
        source: "statemachine.scxml"
    }
}

A compiled state machine can be instantiated the same way as any C++ object:

 
Sélectionnez
auto *stateMachine = new MyStatemachine;

Or:

 
Sélectionnez
MyStatemachine stateMachine;

To use a compiled state machine in QML, you can register it as a QML type:

 
Sélectionnez
struct MyStateMachineRegistration {
    Q_GADGET
    QML_NAMED_ELEMENT(MyStateMachine)
    QML_FOREIGN(MyStateMachine)
    QML_ADDED_IN_VERSION(1, 0)
};

Then you can instantiate it in QML, like this:

 
Sélectionnez
import MyStateMachine 1.0

MyStateMachine {
    id: stateMachine
}

To compile a state machine, the following lines have to be added to the project build file:

When using cmake:

 
Sélectionnez
find_package(Qt6 REQUIRED COMPONENTS Scxml)
target_link_libraries(mytarget PRIVATE Qt6::Scxml)
 
Sélectionnez
qt6_add_statecharts(mytarget
    MyStatemachine.scxml
)

When using qmake:

 
Sélectionnez
QT += scxml
 
Sélectionnez
STATECHARTS = MyStatemachine.scxml

This will tell qmake to run qscxmlc which generates MyStatemachine.h and MyStatemachine.cpp, and adds them to appropriately to the project headers and sources. By default, the generated files are saved in the build directory. The qmake QSCXMLC_DIR or cmake OUTPUT_DIRECTORY variable can be set to specify another directory. The qmake QSCXMLC_NAMESPACE or cmake 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:

 
Sélectionnez
stateMachine->connectToState("red", [](bool active) {
    qDebug() << (active ? "entered" : "exited") << "the red state";

And in QML:

 
Sélectionnez
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:

 
Sélectionnez
stateMachine->connectToEvent("playbackStopped", [](const QScxmlEvent &){
    qDebug() << "Stopped!";
});

And in QML:

 
Sélectionnez
import QtScxml

EventConnection {
    stateMachine: stateMachine
    events: ["playbackStopped"]
    onOccurred: console.log("Stopped!")
}

Sending events to a state machine is equally simple:

 
Sélectionnez
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:

 
Sélectionnez
stateMachine.submitEvent("tap", {
    "artist": "Fatboy Slim"
    "title": "The Rockafeller Skank"
})

A state machine needs a 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.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+