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

news2024/12/31 5:11:35

路流程
流程设计状态图

#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

#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";
    });
}

#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

#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 控制类

#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

#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 .每个状态对应一个流程
2. 每个状态进入后开始执行流程动作
3. 状态进入流程开始执行,执行结束线程结束
4. 线程结束信号控制转移到下一个状态,也就是下一个流程继续往下走
5. 暂停时候主动触发 pause 信号状态机从 work 状态跳出到 pause 状态
6. 恢复时候从 pause 状态回到 history 状态,根据需要设置历史状态深浅,是否记录子状态,还是只记录第一层状态
7. 每个子状态流程末尾使用 final 状态标记,使用他的finished 信号进行状态转移
8. 每个子状态设置初始状态,也就是子状态第一个状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2158908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手写Spring第三篇,原来Spring容器是使用反射来初始化对象的

上次是不是你小子和大家说你拿来做登记的样品被我收了&#xff0c;然后取豆子的时候就是这个样品的&#xff1f; 今天我来辟一下谣&#xff0c;真的是这样的。这小子的样品确实被我收了&#xff0c;不过这小子没给真东西给我&#xff0c;只给了一个指针&#xff0c;害我宝贝得存…

【深度】为GPT-5而生的「草莓」模型!从快思考—慢思考到Self-play RL的强化学习框架

原创 超 超的闲思世界 2024年09月11日 19:17 北京 9月11日消息&#xff0c;据外媒The Information昨晚报道&#xff0c;OpenAI的新模型「草莓」&#xff08;Strawberry&#xff09;&#xff0c;将在未来两周内作为ChatGPT服务的一部分发布。 「草莓」项目是OpenAI盛传已久的…

QT中添加资源文件(一看就会)

QT中添加资源文件 什么是资源文件如何使用创建资源文件编辑资源文件代码中引用资源什么是资源文件 项目中经常需要添加图片、‌音频、‌视频、翻译文件等文件,在QT中,这些文件会放在 .qrc 文件中来被使用。 .qrc 文件是一个XML格式的资源集合描述文件,是Qt中用于定义和管理…

Fyne ( go跨平台GUI )中文文档-入门(一)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI )…

【一文看懂】Gumroad如何购物?Gumroad如何付款?Gumroad支付方式有哪些?Gumroad国内如何支付?

1.Gumroad付款方式 详情移步至底部原文查看~ 3.2.Gumroad数字商品的标价 详情移步至底部原文查看~ 点击【Pay】后&#xff0c;等待一会即可付款成功&#xff0c;点击【Download】即可下载购买的数字商品。 4.注意事项 详情移步至底部原文查看~ Gumroad如何购物&#xff1f;G…

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建Mysql集群

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建Mysql集群 MySQL 集群是一种高可用性、高性能的数据库解决方案&#xff0c;旨在支持分布式应用程序&#xff0c;允许多个 MySQL 实例以集群的方式共同工作&#xff0c;提供数据冗余和故障恢复能力 搭建Mysql集群…

计算机毕业设计之:基于微信小程序的中药材科普系统(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

优青博导团队指导-实验设计、实验结果分析、测序分析及SCI论文辅助

组蛋白甲基化修饰工具(H3K4me3 ChIP-seq) 组蛋白甲基化类型也有很多种&#xff0c;包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守&#xff0c;是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…

【小bug】使用 RestTemplate 工具从 JSON 数据反序列化为 Java 对象时报类型转换异常

起因&#xff1a;今天编写一个请求时需要通过RestTemplate调用外部接口&#xff0c;获取一些信息&#xff0c;但是在获取了外部接口响应内容后&#xff0c;使用强制转换发现报了类型转换异常。之前也遇到过&#xff0c;但是没记录下来&#xff0c;今天又查了一遍……干脆记录一…

Algo-Lab 2 Stack Queue ADT

Lab 2: Stack & Queue ADT Part 1 ​ 这里只说一下最小栈的思路&#xff0c;我们可以在定义一个栈&#xff0c;来同步存储当前情况下的占的最小值。最小栈第一时间的想法可能是设定一个变量&#xff0c;每次push进来栈中的元素进行对比&#xff0c;保持最小值&#xff0c;…

Redis渐进式遍历

我们知道&#xff0c;keys* 是一次性把所有的key都获取到&#xff0c;这个操作太危险&#xff0c;可能会一次性得到太多的key而阻塞服务器。但是通过渐进式遍历&#xff0c;既能够获取到所有的key&#xff0c;又能不会卡死服务器。 redis使用scan命令进行渐进式遍历&#xff0…

宠物去浮毛救星?希喂、小米、霍尼韦尔宠物空气净化器哪款好用

怎么有人放假也不开心&#xff1f; 快到的国庆假期真是愁死我了...本来我妈国庆去旅游&#xff0c;我就打算不回家&#xff0c;和我家猫过二人世界。结果突然有事&#xff0c;我妈取消出行&#xff0c;改成让我假期回家陪她。我回家容易&#xff0c;我家猫回去可难啊&#xff…

前端-js例子:todolist

实现效果图&#xff1a; 实现步骤&#xff1a; 1.body部分 1.首先&#xff0c;设置输入数据的框和按钮进行操作 2.设置一个表格标签&#xff08;有边框&#xff09;&#xff0c;首先在表头放置两列&#xff08;“事项”‘’操作&#xff09; <body><div class"…

初学者怎么入门大语言模型(LLM)?看完这篇你就懂了!

当前2024年&#xff0c;LLM领域发展日新月异&#xff0c;很多新的实用技术层出不穷&#xff0c;个人认为要跟上LLM的发展&#xff0c;需要掌握以下内容&#xff0c;并需要不断地跟踪学习。 入门LLM前置基础 深度学习基础知识&#xff1a;推荐李宏毅的深度学习课程Python和num…

数据结构2——单链表

目录 1.链表 1.1链表的概念及结构 1.2 链表的分类 ​编辑2.无头单链表的实现 1. 节点 2.遍历链表 3.动态增加新节点 4.查找&#xff08;修改&#xff09; 5.插入 5.1 尾插 5.2 头插 5.3 在pos之前插入x 5.4 在pos之后插入x 6.删除 6.1 尾删 6.2 头删 6.3 删除…

DPDK 简易应用开发之路 4:基于Pipeline模型的DNS服务器

本机环境为 Ubuntu20.04 &#xff0c;dpdk-stable-20.11.10 使用scapy和wireshark发包抓包分析结果 完整代码见&#xff1a;github Pipeline模型 DPDK Pipeline模型是基于Data Plane Development Kit&#xff08;DPDK&#xff09;的高性能数据包处理框架。它通过将数据流分为多…

基于SpringBoot+Vue+MySQL的旅游推荐管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着社会的快速发展和人民生活水平的显著提高&#xff0c;旅游已成为人们休闲娱乐的重要方式。然而&#xff0c;面对海量的旅游信息和多样化的旅游需求&#xff0c;如何高效地管理和推荐旅游资源成为了一个亟待解决的问题。因此…

学习记录:js算法(四十三):翻转二叉树

文章目录 翻转二叉树我的思路网上思路递归栈 总结 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点 图一&#xff1a; 图二&#xff1a; 示例 1&#xff1a;&#xff08;如图一&#xff09; 输入&#xff1a;root [4,2,7,1…

大模型价格战,打到了负毛利,卷or不卷?

国产大模型淘汰赛在加速。这轮淘汰赛会持续一两年&#xff0c;只有少数真正具备实力的基础模型企业能继续活下去 中国市场的大模型价格战已经打了近半年。这轮价格战已经打到了负毛利&#xff0c;而且暂时没有停止迹象。头部云厂商仍在酝酿新一轮降价。这轮降价会在今年9月下旬…

视频单目标跟踪研究

由于对视频单目标跟踪并不是很熟悉&#xff0c;所以首先得对该领域有个大致的了解。 视频目标跟踪是计算机视觉领域重要的基础性研究问题之一&#xff0c;是指在视频序列第一帧指定目标 后&#xff0c;在后续帧持续跟踪目标&#xff0c;即利用边界框&#xff08;通常用矩形框表…