Qt 状态机编程,双层状态机,实现暂停恢复
流程设计状态图
#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. 每个子状态设置初始状态,也就是子状态第一个状态