使用Qt Creator创建和编辑状态图详细教程
- [一、使用Qt Creator创建和编辑状态图](#一、使用Qt Creator创建和编辑状态图)
- 二、如何使用状态图
- [三、Qt SCXML 模块详解](#三、Qt SCXML 模块详解)
-
- [1、SCXML 概述](#1、SCXML 概述)
- [2、Qt SCXML 模块的作用](#2、Qt SCXML 模块的作用)
- [3、使用 Qt SCXML 模块的基本步骤](#3、使用 Qt SCXML 模块的基本步骤)
-
- [3.1 编写 SCXML 文件](#3.1 编写 SCXML 文件)
- [3.2 (可选但推荐) 使用 `qscxmlc` 编译 SCXML 文件](#3.2 (可选但推荐) 使用
qscxmlc编译 SCXML 文件) - [3.3 在 Qt 项目中集成](#3.3 在 Qt 项目中集成)
- 1、关键特性与优势
- 5、示例:编译后状态机的使用 (C++)
- 6、总结
一、使用Qt Creator创建和编辑状态图
1、创建新项目



2、新建scxml文件



3、编辑状态图实现下面这个状态
xml
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="MainControl">
<!-- 主控制状态 -->
<state id="MainControl">
<initial>
<transition target="Stopped"/>
</initial>
<!-- 设备停止状态 -->
<state id="Stopped">
<onentry>
<log expr="'设备已停止'"/>
</onentry>
<transition event="start" target="Running"/>
</state>
<!-- 设备运行状态 -->
<state id="Running" initial="Preparing">
<onentry>
<log expr="'设备启动中...'"/>
</onentry>
<!-- 准备阶段 -->
<state id="Preparing">
<transition event="ready" target="Working"/>
</state>
<!-- 工作阶段 -->
<state id="Working">
<transition event="emergency.stop" target="Stopped"/>
<transition event="pause" target="Paused"/>
</state>
<!-- 暂停状态 -->
<state id="Paused">
<transition event="resume" target="Working"/>
<transition event="emergency.stop" target="Stopped"/>
</state>
</state>
</state>
<!-- 并行电池监控状态 -->
<parallel id="BatteryMonitor">
<state id="Normal">
<transition cond="BatteryLevel < 20" target="LowBattery"/>
</state>
<state id="LowBattery">
<onentry>
<log expr="'警告:电量不足!'"/>
</onentry>
<transition cond="BatteryLevel >= 20" target="Normal"/>
</state>
</parallel>
<!-- 全局事件处理 -->
<transition event="system.shutdown" target="Shutdown"/>
<final id="Shutdown">
<onentry>
<log expr="'系统关闭'"/>
</onentry>
</final>
</scxml>

单击状态会出现箭头

绘制完成

查看结果:
xml
<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early" xmlns:qt="http://www.qt.io/2015/02/scxml-ext" name="MainControl" qt:editorversion="18.0.0" initial="Stopped">
<qt:editorinfo initialGeometry="221.80;107.85;-20;-20;40;40"/>
<state id="Stopped">
<qt:editorinfo scenegeometry="535.18;129.21;475.18;79.21;120;100" geometry="535.18;129.21;-60;-50;120;100"/>
<transition type="external" event="start" target="Running"/>
</state>
<state id="Running">
<qt:editorinfo scenegeometry="419.70;326.60;-174.47;359.95;1419.29;255.59" geometry="419.70;326.60;-594.16;33.35;1419.29;255.59"/>
<state id="Preparing">
<qt:editorinfo scenegeometry="383.59;291.38;323.59;241.38;120;100" geometry="-490.41;161.15;-60;-50;120;100"/>
<transition type="external" event="ready" target="Working"/>
</state>
<state id="Working">
<qt:editorinfo scenegeometry="471.49;487.75;411.49;437.75;120;100" geometry="51.79;161.15;-60;-50;120;100"/>
<transition type="external" event="pause" target="Paused"/>
</state>
<state id="Paused">
<qt:editorinfo scenegeometry="1616.74;291.38;1556.74;241.38;120;100" geometry="742.74;161.15;-60;-50;120;100"/>
<transition type="external" event="resume" target="Working"/>
</state>
</state>
</scxml>
其余自己添加
二、如何使用状态图
参考我这篇文档:Qt SCXML 模块详解
三、Qt SCXML 模块详解
1、SCXML 概述
SCXML (State Chart XML) 是一种基于 XML 的 W3C 标准,用于描述复杂的状态机(State Machines)。它提供了一种形式化的方式来定义:
- 状态(States):如
初始状态、最终状态、复合状态(包含子状态)、并行状态。 - 转换(Transitions):状态之间的迁移路径,由
事件触发,并可带有条件和执行的动作。 - 事件(Events):触发状态转换的信号。
- 动作(Actions):在进入/退出状态或执行转换时执行的逻辑,如发送事件、调用脚本、操作数据模型等。
- 数据模型(Data Model):用于存储状态机上下文相关的数据。
2、Qt SCXML 模块的作用
Qt 的 SCXML 模块 (QtSCXML) 提供了在 Qt 应用程序中使用 SCXML 标准的能力。其主要组件包括:
- QScxmlStateMachine :核心类,代表一个 SCXML 状态机实例。它:
- 解析 SCXML 文件或字符串。
- 管理状态机的生命周期(初始化、启动、停止)。
- 提供接口与状态机交互:发送事件、查询当前状态、订阅状态变化通知等。
- 可以与 Qt 的信号/槽机制集成。
- SCXML 编译器 (
qscxmlc) :一个命令行工具(或可通过 CMake/QMake 集成),用于将 SCXML 文件编译成 C++ 代码(.h和.cpp文件)。- 目的:提升运行时性能(避免 XML 解析开销)和类型安全性(生成的类提供事件类型和属性访问器)。
- 生成内容 :一个继承自
QScxmlStateMachine的特定状态机类。该类:- 提供强类型的事件发送方法(如
submitEventName()代替通用的submitEvent("EventName"))。 - 提供访问 SCXML 数据模型中定义的数据属性的方法(如
property()或生成的 getter/setter)。 - 为每个状态定义了枚举常量(便于查询当前状态)。
- 提供强类型的事件发送方法(如
- Qt 状态机集成 :虽然 SCXML 本身功能强大,但
QScxmlStateMachine可以无缝地与 Qt 的事件循环和对象系统协作。
3、使用 Qt SCXML 模块的基本步骤
3.1 编写 SCXML 文件
使用文本编辑器或专门的 SCXML 编辑器(如 qscxml 提供的 qscxmlmon)创建描述状态机的 .scxml 文件。例如,一个简单的开关状态机:
xml
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="off">
<state id="off">
<transition event="switch" target="on"/>
</state>
<state id="on">
<transition event="switch" target="off"/>
</state>
</scxml>
3.2 (可选但推荐) 使用 qscxmlc 编译 SCXML 文件
-
命令行 :
bashqscxmlc -o LightSwitchMachine.h LightSwitchMachine.scxml -
CMake :
cmakefind_package(Qt6 COMPONENTS SCXML REQUIRED) qt_add_scxml_file(LightSwitchMachine "LightSwitchMachine.scxml" OUTPUT_HEADER LightSwitchMachine.h OUTPUT_SOURCE LightSwitchMachine.cpp) -
qmake :
qmakescxml_files = LightSwitchMachine.scxml qscxmlc.commands = qscxmlc -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} QMAKE_EXTRA_COMPILERS += scxmlc
3.3 在 Qt 项目中集成
-
配置项目 :确保项目文件(
.pro,CMakeLists.txt)包含scxml模块。- qmake:
QT += scxml - CMake:
find_package(Qt6 COMPONENTS SCXML REQUIRED)和target_link_libraries(myapp Qt6::SCXML)
- qmake:
-
包含头文件 :如果使用了
qscxmlc,包含生成的头文件#include "LightSwitchMachine.h";否则使用#include <QtScxml/QScxmlStateMachine>。 -
创建状态机实例 :
-
未编译 :
cppQScxmlStateMachine *machine = QScxmlStateMachine::fromFile(":/LightSwitchMachine.scxml"); -
已编译 :
cppLightSwitchMachine *machine = new LightSwitchMachine();
-
-
启动状态机 :
cppmachine->start(); -
与状态机交互 :
-
发送事件 :
cpp// 未编译 (通用方法) machine->submitEvent("switch"); // 已编译 (类型安全方法) machine->submitSwitch(); // 假设事件名为 'switch' -
查询状态 :
cppQString currentState = machine->activeStateNames().first(); // 获取根状态下的活动状态名 // 已编译 (使用枚举) if (machine->isActive(LightSwitchMachine::On)) { ... } -
连接信号 :
cpp// 状态进入/退出信号 connect(machine, &QScxmlStateMachine::reachedStableState, this, &MyClass::onStableState); connect(machine, &QScxmlStateMachine::stateEntered, this, &MyClass::onStateEntered); connect(machine, &QScxmlStateMachine::stateExited, this, &MyClass::onStateExited); // 已编译状态机可能有更具体的信号
-
1、关键特性与优势
- 可视化与形式化:SCXML 文件可以可视化编辑,状态机行为清晰定义。
- 复用性:状态机定义(SCXML 文件)独立于业务逻辑代码。
- 可维护性:复杂状态逻辑集中管理,易于修改。
- 性能:编译后的状态机运行高效。
- 集成:与 Qt 的信号/槽、事件循环完美结合。
- 复杂状态支持:支持嵌套状态、并行状态、历史状态等。
5、示例:编译后状态机的使用 (C++)
cpp
#include "LightSwitchMachine.h" // 由 qscxmlc 生成
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
LightSwitchMachine machine;
machine.start(); // 启动状态机,初始状态为 "off"
// 连接信号查看状态变化
QObject::connect(&machine, &LightSwitchMachine::onEntered, [](const QString &state) {
qDebug() << "Entered state:" << state;
});
// 发送事件切换状态
machine.submitSwitch(); // 从 off -> on
machine.submitSwitch(); // 从 on -> off
return app.exec();
}
6、总结
Qt 的 SCXML 模块为在 Qt 应用程序中实现基于标准的、复杂的、可维护的状态机行为提供了强大的支持。通过编写 SCXML 文件定义状态逻辑,利用 QScxmlStateMachine 运行,并可选地使用 qscxmlc 编译器提升性能和类型安全,开发者能够高效地管理应用的状态流转。
