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

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

一、使用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 &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 复制代码
<?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 文件

  • 命令行

    bash 复制代码
    qscxmlc -o LightSwitchMachine.h LightSwitchMachine.scxml
  • CMake

    cmake 复制代码
    find_package(Qt6 COMPONENTS SCXML REQUIRED)
    qt_add_scxml_file(LightSwitchMachine "LightSwitchMachine.scxml" OUTPUT_HEADER LightSwitchMachine.h OUTPUT_SOURCE LightSwitchMachine.cpp)
  • qmake

    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. 创建状态机实例

    • 未编译

      cpp 复制代码
      QScxmlStateMachine *machine = QScxmlStateMachine::fromFile(":/LightSwitchMachine.scxml");
    • 已编译

      cpp 复制代码
      LightSwitchMachine *machine = new LightSwitchMachine();
  4. 启动状态机

    cpp 复制代码
    machine->start();
  5. 与状态机交互

    • 发送事件

      cpp 复制代码
      // 未编译 (通用方法)
      machine->submitEvent("switch");
      // 已编译 (类型安全方法)
      machine->submitSwitch(); // 假设事件名为 'switch'
    • 查询状态

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

相关推荐
_OP_CHEN5 小时前
【从零开始的Qt开发指南】(十)Qt 常用控件之输入类控件全攻略:7 大控件从入门到实战,覆盖所有输入场景
开发语言·c++·qt·前端开发·qt常用控件·gui图形化界面·qt输入类控件
枫叶丹45 小时前
【Qt开发】Qt窗口(十) -> QInputDialog 输入对话框
c语言·开发语言·数据库·c++·qt
小灰灰搞电子15 小时前
Qt 重写QRadioButton实现动态radioButton源码分享
开发语言·qt·命令模式
刺客xs18 小时前
Qt----事件简述
开发语言·qt
27399202918 小时前
QButtonGroup (Qt)
qt
程序员-King.18 小时前
【Qt开源项目】— ModbusScope-进度规划
开发语言·qt
Y1rong20 小时前
QT之简陋版网络调试助手
qt
小尧嵌入式21 小时前
C语言中的面向对象思想
c语言·开发语言·数据结构·c++·单片机·qt
程序员-King.21 小时前
【Qt开源项目】— ModbusScope-day 4
开发语言·qt