详细介绍:使用Qt Creator创建和编辑状态图详细教程

一、使用Qt Creator创建和编辑状态图

1、创建新项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、新建scxml文件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、编辑状态图实现下面这个状态

<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 &lt; 20" target="LowBattery"/>
                  </state>
                    <state id="LowBattery">
                    <onentry>
                      <log expr="'警告:电量不足!'"/>
                    </onentry>
                      <transition cond="BatteryLevel &gt;= 20" target="Normal"/>
                    </state>
                  </parallel>
                  <!-- 全局事件处理 -->
                    <transition event="system.shutdown" target="Shutdown"/>
                      <final id="Shutdown">
                      <onentry>
                        <log expr="'系统关闭'"/>
                      </onentry>
                    </final>
                  </scxml>

在这里插入图片描述
单击状态会出现箭头
在这里插入图片描述
绘制完成
在这里插入图片描述
查看结果:

<?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 文件。例如,一个简单的开关状态机:

<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 文件

  • 命令行
    qscxmlc -o LightSwitchMachine.h LightSwitchMachine.scxml
  • CMake
    find_package(Qt6 COMPONENTS SCXML REQUIRED)
    qt_add_scxml_file(LightSwitchMachine "LightSwitchMachine.scxml" OUTPUT_HEADER LightSwitchMachine.h OUTPUT_SOURCE LightSwitchMachine.cpp)
  • qmake
    scxml_files = LightSwitchMachine.scxml
    qscxmlc.commands = qscxmlc -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
    QMAKE_EXTRA_COMPILERS += scxmlc

3.3 在 Qt 项目中集成

  1. 配置项目:确保项目文件(.pro, CMakeLists.txt)包含 scxml 模块。
    • qmake: QT += scxml
    • CMake: find_package(Qt6 COMPONENTS SCXML REQUIRED)target_link_libraries(myapp Qt6::SCXML)
  2. 包含头文件:如果使用了 qscxmlc,包含生成的头文件 #include "LightSwitchMachine.h";否则使用 #include <QtScxml/QScxmlStateMachine>
  3. 创建状态机实例
    • 未编译
      QScxmlStateMachine *machine = QScxmlStateMachine::fromFile(":/LightSwitchMachine.scxml");
    • 已编译
      LightSwitchMachine *machine = new LightSwitchMachine();
  4. 启动状态机
    machine->start();
  5. 与状态机交互
    • 发送事件
      // 未编译 (通用方法)
      machine->submitEvent("switch");
      // 已编译 (类型安全方法)
      machine->submitSwitch(); // 假设事件名为 'switch'
    • 查询状态
      QString currentState = machine->activeStateNames().first(); // 获取根状态下的活动状态名
      // 已编译 (使用枚举)
      if (machine->isActive(LightSwitchMachine::On)) { ... }
    • 连接信号
      // 状态进入/退出信号
      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++)

#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 编译器提升性能和类型安全,开发者能够高效地管理应用的状态流转。

在这里插入图片描述

posted @ 2026-01-13 22:01  gccbuaa  阅读(30)  评论(0)    收藏  举报