实例化状态机

动态创建的状态机和编译的状态机的行为方式、属性、状态、数据模型等都是一样的。它们的区别只在于实例化的方式不同。要在 C++ 中从 SCXML 文件动态创建状态机,可以使用

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)
qt_add_statecharts(mytarget
    MyStatemachine.scxml
)

使用 qmake 时

QT += scxml
STATECHARTS = MyStatemachine.scxml

这会告诉qmake运行qscxmlc,生成 MyStatemachine.h 和 MyStatemachine.cpp,并将它们适当地添加到项目头文件和源文件中。默认情况下,生成的文件保存在构建目录中。可以设置 qmakeQSCXMLC_DIR或 cmakeOUTPUT_DIRECTORY变量来指定其他目录。qmakeQSCXMLC_NAMESPACE或 cmakeNAMESPACE变量可用于将状态机代码放入 C++ 命名空间。

实例化状态机后,可按如下方法连接任意状态的活动属性。例如,如果交通信号灯的状态机有一个表示红灯的状态(在 scxml 文件中该状态的 id 为 "red"),你可以写入

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

而在 QML 中

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

如果你想在状态机发送事件时得到通知,你可以连接到相应的信号。例如,一个媒体播放器状态机通过发送事件来指示播放已停止,你可以写入

stateMachine->connectToEvent("playbackStopped", [](constQScxmlEvent&){    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" }
}));

这将生成一个 "tap "事件,其地图内容可在状态机内的 _event.data 中找到。在 QML:

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

注意: 状态机需要QEventLoop 才能正常工作。事件循环用于为事件实现delay 属性,并在收到嵌套(或父)状态机的事件时安排状态机的处理。QML 应用程序或 widget 应用程序将始终运行事件循环,因此不需要额外的东西。对于其他应用程序,必须调用QApplication::run 才能启动事件循环处理。

© 2025 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.