Qt 状态机编程,双层状态机,实现暂停恢复

流程设计状态图

cpp 复制代码
#ifndef WORKMACHINE_H
#define WORKMACHINE_H

#include <QObject>
#include <QStateMachine>
#include <QHistoryState>
#include <QFinalState>

#include "WorkThread.h"

class WorkMachine : public QObject
{
    Q_OBJECT
public:
    explicit WorkMachine(QObject *parent = nullptr);
    ~WorkMachine();

    void startMachine();
    void runMachineWorkFlow();
    void pauseMachine();
    void resumeMachine();

signals:
    void sigMachineLog(QString log);
    void sigNextState();
    void sigPauseMachine();
    void sigResumeMachine();
    void sigMachineState(int state);

private:
    void initMachine();
    void initStateTrans();
    void initWork();

private:
    // 待机-》 (开门-》关门-》清洗-》甩干-》)  结束
    QStateMachine   m_machine;
    QState          *m_idleState;
    QState          *m_stateOpen;
    QState          *m_stateClose;
    QState          *m_groupStateWork;
    QState          *m_stateWash;
    QState          *m_stateDry;
    QState          *m_statePause;
    QHistoryState   *m_stateHistoryWork;
    bool            m_isPause;
    WorkThread      *m_workThread;
};

#endif // WORKMACHINE_H
cpp 复制代码
#include "WorkMachine.h"
#include <QDebug>

WorkMachine::WorkMachine(QObject *parent)
    : QObject{parent}
{
    initMachine();
    initStateTrans();
    initWork();
    m_isPause = false;
}

WorkMachine::~WorkMachine()
{
    m_groupStateWork->deleteLater();
}

void WorkMachine::startMachine()
{
    if (m_machine.isRunning()) {
        qDebug() << " ********* stop **********";
        m_machine.stop();
        emit sigMachineState(0);
    }
    else {
        qDebug() << "******** machine start work ********";
        m_machine.start();
        emit sigMachineState(1);
        //emit sigMachineLog("******** machine start work ********")
    }
}

void WorkMachine::runMachineWorkFlow()
{
    emit sigNextState();
}

void WorkMachine::pauseMachine()
{
    emit sigPauseMachine();

    m_isPause = true;
}

void WorkMachine::resumeMachine()
{
    emit sigResumeMachine();
    m_isPause = false;
}

void WorkMachine::initMachine()
{
    m_workThread = new WorkThread();

    m_idleState = new QState(&m_machine);
    m_idleState->setObjectName("initialState");
    m_statePause = new QState(&m_machine);
    m_statePause->setObjectName("pauseState");

    m_groupStateWork = new QState(&m_machine);
    m_groupStateWork->setObjectName("stateWork");

    m_stateOpen = new QState(m_groupStateWork);
    m_stateOpen->setObjectName("openState");

    QState *open1 = new QState(m_stateOpen);
    open1->setObjectName("open1State");
    QState *open2 = new QState(m_stateOpen);
    QFinalState *openFinal  = new QFinalState(m_stateOpen);

    open2->setObjectName("open2State");
    m_stateOpen->setInitialState(open1);
    open1->addTransition(this, &WorkMachine::sigNextState, open2);
    open2->addTransition(this, &WorkMachine::sigNextState, openFinal);
    connect(open1, &QState::entered, this, [this](){
        m_workThread->startTask("step 1 open1", 500);
    });
    connect(open2, &QState::entered, this, [this](){
        m_workThread->startTask("step 1 open2", 500);
    });

    m_stateClose = new QState(m_groupStateWork);
    m_stateClose->setObjectName("closeState");

    m_stateWash = new QState(m_groupStateWork);
    m_stateWash->setObjectName("stateWash");

    m_stateDry = new QState(m_groupStateWork);
    m_stateDry->setObjectName("stateDry");

    m_stateHistoryWork = new QHistoryState(m_groupStateWork);
    m_stateHistoryWork->setObjectName("historyState");
    m_stateHistoryWork->setDefaultState(m_stateWash);
    m_stateHistoryWork->setHistoryType(QHistoryState::DeepHistory);

    m_groupStateWork->setChildMode(QState::ExclusiveStates);
    m_groupStateWork->setInitialState(m_stateHistoryWork);
    m_machine.setInitialState(m_idleState);
}

void WorkMachine::initStateTrans()
{
    m_groupStateWork->addTransition(this, &WorkMachine::sigPauseMachine, m_statePause);
    m_statePause->addTransition(this, &WorkMachine::sigResumeMachine, m_stateHistoryWork);

    connect(m_workThread, &WorkThread::finished, this, [this](){
        if (m_isPause) {

        }
        else {
            emit sigNextState();
        }
    });

    m_idleState->addTransition(this, &WorkMachine::sigNextState, m_stateOpen);
    //m_stateOpen->addTransition(this, &WorkMachine::sigNextState, m_stateClose);
    m_stateOpen->addTransition(m_stateOpen, &QState::finished, m_stateClose);
    m_stateClose->addTransition(this, &WorkMachine::sigNextState, m_stateWash);
    m_stateWash->addTransition(this, &WorkMachine::sigNextState, m_stateDry);
    m_stateDry->addTransition(this, &WorkMachine::sigNextState, m_idleState);
}

void WorkMachine::initWork()
{
    connect(m_idleState, &QState::entered, this, [this](){
        qDebug() << "init state";
    });

    connect(m_stateHistoryWork, &QState::entered, this, [this](){
        qDebug() << "m_stateHistoryWork state enter";
    });

    connect(m_stateOpen, &QState::entered, this, [this](){
        m_workThread->startTask("step 1 Open");
    });

    connect(m_stateClose, &QState::entered, this, [this](){
        m_workThread->startTask("step 2 Close");
    });

    connect(m_groupStateWork, &QState::entered, this, [this](){
        qDebug() << "Work state enter";
    });

    connect(m_stateWash, &QState::entered, this, [this](){
        m_workThread->startTask("step 3 Wash", 2000);
    });

    connect(m_stateDry, &QState::entered, this, [this](){
        m_workThread->startTask("step 4 Dry", 2000);
    });

    connect(m_statePause, &QState::entered, this, [this](){
        qDebug() << "pause";
    });
}
cpp 复制代码
#ifndef WORKTHREAD_H
#define WORKTHREAD_H

#include <QObject>
#include <QThread>

class WorkThread: public QThread
{
public:
    WorkThread();
    void startTask(QString log, int timems=500);
    void run() override;

private:
    QString   m_log;
    int       m_time;
};

#endif // WORKTHREAD_H
cpp 复制代码
#include "WorkThread.h"
#include <QDebug>

WorkThread::WorkThread() {

}

void WorkThread::startTask(QString log, int timems)
{
    m_log = log;
    m_time = timems;
    this->start();
}

void WorkThread::run()
{
    QThread::msleep(100);
    qDebug() << m_log  + " start running ...";

    QThread::msleep(m_time);
    qDebug() << m_log  + " end";
}

UI 控制类

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "WorkMachine.h"

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_btnRun_clicked();

private:
    Ui::Widget *ui;
    WorkMachine  m_machine;
};
#endif // WIDGET_H
cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(ui->btnStart, &QPushButton::clicked, this, [this](){
        m_machine.startMachine();
    });

    connect(ui->btnPause, &QPushButton::clicked, this, [this](){
        m_machine.pauseMachine();
    });

    connect(ui->btnResume, &QPushButton::clicked, this, [this](){
        m_machine.resumeMachine();
    });

    connect(&m_machine, &WorkMachine::sigMachineState, this, [this](bool isRun){
        ui->btnPause->setEnabled(isRun);
    });
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btnRun_clicked()
{
    m_machine.runMachineWorkFlow();
}

设计思路:

1 .每个状态对应一个流程

  1. 每个状态进入后开始执行流程动作

  2. 状态进入流程开始执行,执行结束线程结束

  3. 线程结束信号控制转移到下一个状态,也就是下一个流程继续往下走

  4. 暂停时候主动触发 pause 信号状态机从 work 状态跳出到 pause 状态

  5. 恢复时候从 pause 状态回到 history 状态,根据需要设置历史状态深浅,是否记录子状态,还是只记录第一层状态

  6. 每个子状态流程末尾使用 final 状态标记,使用他的finished 信号进行状态转移

  7. 每个子状态设置初始状态,也就是子状态第一个状态

相关推荐
程序喵大人3 分钟前
【C++进阶】STL算法与函数对象 -【C++进阶】STL算法与函数对象
开发语言·c++·算法
牛马也想出海23 分钟前
使用Playwright被检测为机器人的原因及反检测方案
开发语言·网络·人工智能·机器人·php
GrowthDiary00730 分钟前
Python 常用函数总结
开发语言·python
热心网友俣先生43 分钟前
2026年华数杯C 题 超详细解题思路
c语言·开发语言·人工智能
啄缘之间1 小时前
5.1 uvm‑component 的层级结构管理? new (name,parent) 参数
开发语言·笔记·学习·ic·uvm·sv
旖旎夜光1 小时前
C++(类与对象)(下)
开发语言·c++·学习
张小凡vip1 小时前
Python爬虫实战:高效稳定的文件下载模块设计与实现
开发语言·爬虫·python
江屿风1 小时前
【科普】【差集&交集概念落地云相册】流食般投喂
开发语言·c++·笔记·算法·云相册
代龙涛1 小时前
WordPress header.php 与 footer.php 模板结构详解
开发语言·php·wordpress
黄贵根7 小时前
JavaScript实现教培行业意向登记系统
开发语言·javascript·ecmascript