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. 每个子状态设置初始状态,也就是子状态第一个状态

相关推荐
郑州光合科技余经理4 小时前
同城系统海外版:一站式多语种O2O系统源码
java·开发语言·git·mysql·uni-app·go·phpstorm
一只乔哇噻4 小时前
java后端工程师+AI大模型开发进修ing(研一版‖day60)
java·开发语言·人工智能·学习·语言模型
LNN20224 小时前
Linuxfb+Qt 输入设备踩坑记:解决 “节点存在却无法读取“ 问题
开发语言·qt
qq_401700414 小时前
Qt单实例程序-----禁止程序多开
qt
foxsen_xia5 小时前
go(基础06)——结构体取代类
开发语言·算法·golang
巨人张5 小时前
C++火柴人跑酷
开发语言·c++
ID_180079054735 小时前
基于 Python 的 Cdiscount 商品详情 API 调用与 JSON 核心字段解析(含多规格 SKU 提取)
开发语言·python·json
悟能不能悟5 小时前
Caused by: java.sql.SQLException: ORA-28000: the account is locked怎么处理
java·开发语言
亦是远方6 小时前
南京邮电大学使用计算机求解问题实验一(C语言简单编程练习)
c语言·开发语言·实验报告·南京邮电大学
社会零时工6 小时前
NVIDIA Jetson开发板使用记录——开发环境搭建
qt·opencv·nvidia