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

相关推荐
阿pin1 分钟前
Android随笔-View绘制流程
android·开发语言·view
敖行客 Allthinker27 分钟前
IM 融合专题:后端架构师的核心修炼
java·开发语言·数据库
进击的程序猿~32 分钟前
Go Slice源码深度解析指南
开发语言·后端·golang
Hesionberger35 分钟前
快速求解完全平方数的最少数量
开发语言·数据结构·python·算法·leetcode·c#
西门吹-禅11 小时前
java springboot N+1问题
java·开发语言·spring boot
skywalk816311 小时前
设计并实现段言的 C FFI 绑定机制 @Trae
c语言·开发语言·python·编程
IT笔记13 小时前
【Rust】Rust Match 模式匹配详解
java·开发语言·rust
2zcode13 小时前
免费开源项目文档:基于MATLAB卷积神经网络的口罩佩戴检测系统
开发语言·matlab·cnn
逝水无殇13 小时前
C# 运算符重载详解
开发语言·后端·c#
TPBoreas14 小时前
配置信息防泄露方案:.env 环境隔离详解(dotenv-java)
java·开发语言