实例化状态机

动态创建的和编译的状态机行为相同,具有相同的属性、状态、数据模型等。它们唯一的差异在于它们创建的方式。要从 SCXML 文件在 C++ 中动态创建一个,可以使用

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

或者,在 QML 中

import QtScxml

Item {
    property StateMachine stateMachine: scxmlLoader.stateMachine

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

编译状态机可以像任何 C++ 对象一样实例化

auto *stateMachine = new MyStatemachine;

或者

MyStatemachine stateMachine;

要在 QML 中使用编译状态机,可以将它注册为一个 QML 类型

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

然后您可以在 QML 中实例化它,如下所示

import MyStateMachine 1.0

MyStateMachine {
    id: stateMachine
}

要编译状态机,必须在项目构建文件中添加以下行

当使用 cmake 时

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

当使用 qmake 时

QT += scxml
STATECHARTS = MyStatemachine.scxml

这将告诉 qmake 运行 qscxmlc,它生成 MyStatemachine.h 和 MyStatemachine.cpp,并将它们添加到项目的头文件和源文件中。默认情况下,生成的文件保存在构建目录中。可以设置 qmake 的 QSCXMLC_DIR 或 cmake 的 OUTPUT_DIRECTORY 变量来指定另一个目录。可以设置 qmake 的 QSCXMLC_NAMESPACE 或 cmake 的 NAMESPACE 变量,以将状态机代码放入 C++ 命名空间。

实例化状态机后,可以连接到任何状态的活动属性,如下所示。例如,如果交通灯的状态机有一个表示灯是红色的状态(在 scxml 文件中具有便利的 id "red"),可以编写

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

并且在 QML 中

Light {
    id: greenLight
    color: "green"
    visible: stateMachine.green
}

如果要在状态机发送事件时接收通知,可以连接到相应的信号。例如,对于通过发送事件表示播放停止的媒体播放器状态机,可以编写

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

并且在 QML 中

import QtScxml

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

向状态机发送事件同样简单

stateMachine->submitEvent("tap", QVariantMap({
    { "artist", "Fatboy Slim" },
    { "title", "The Rockafeller Skank" }
}));

这将在状态机内部生成一个具有 _event.data 中可用内容的 "tap" 事件。在 QML 中

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

注意:状态机需要一个 QEventLoop 才能正确工作。事件循环用于实现事件的 delay 属性,并在从嵌套(或父)状态机接收到事件时安排状态机的处理。QML 应用程序或小部件应用程序始终有一个运行的事件循环,所以不需要额外的东西。对于其他应用程序,必须调用 QApplication::run 来启动事件循环处理。

© 2024 The Qt Company Ltd. 本文档收录的贡献版权属于其各自的所有者。本提供的文档是在 Free Software Foundation 发布的 GNU 自由文档许可协议版本 1.3 的条款下许可的。Qt 和相应的标志是 The Qt Company Ltd. 在芬兰和/或其他国家的商标。所有其他商标均为其各自所有者的财产。