Qt之QStateMachine等待
在项目中经常需要等待,我们模拟0-30的数,假如我们其中5, 25的数需要进行等待,等待用户处理完自己事情后,按下按钮继续,找Qt的项目中有一个
QStateMachine
qstatemmachine类提供了一个分层有限状态机。
QStateMachine基于Statecharts的概念和符号。qstatemmachine是状态机框架的一部分。
状态机管理一组状态(从QAbstractState继承的类)和这些状态之间的转换(QAbstractTransition的后代);这些状态和转换定义了一个状态图。一旦构建了状态图,状态机就可以执行它。qstatemmachine的执行算法基于状态图XML (SCXML)算法。该框架的概述给出了几个状态图和构建它们的代码。
使用addState()函数向状态机添加顶级状态。使用removeState()函数删除状态。不鼓励在机器运行时删除状态。
在机器启动之前,必须设置初始状态。初始状态是机器启动时进入的状态。然后可以启动状态机。当进入初始状态时,就会发出started()信号。
机器是事件驱动的,并保持自己的事件循环。事件通过postEvent()发送到机器。请注意,这意味着它是异步执行的,并且如果没有正在运行的事件循环,它将无法进行。你通常不需要将事件直接发布到机器上,因为Qt的转换,例如,QEventTransition和它的子类,会处理这个。但是对于由事件触发的自定义转换,postEvent()很有用。
状态机处理事件并进行转换,直到进入顶级最终状态;然后状态机发出finished()信号。您还可以显式地stop()状态机。在这种情况下,会发出stopped()信号。
下面的代码片段显示了一个状态机,当按钮被点击时,状态机将完成:
QPushButton button;
QStateMachine machine;
QState *s1 = new QState();
s1->assignProperty(&button, "text", "Click me");
QFinalState *s2 = new QFinalState();
s1->addTransition(&button, SIGNAL(clicked()), s2);
machine.addState(s1);
machine.addState(s2);
machine.setInitialState(s1);
machine.start();
那么我们实现自己
Processor类
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include <QObject>
#include <QStateMachine>
#include <QState>
#include <QFinalState>
class Processor : public QObject
{
Q_OBJECT
public:
explicit Processor(QObject *parent = nullptr);
void startProcessing();
void resumeProcessing();
signals:
void progressUpdated(int value);
void runSig();
void paused();
void finished();
private:
void processNextItem();
bool isRunning() const;
private:
QStateMachine *m_machine;
QState *m_runningState;
QState *m_pausedState;
QFinalState *m_finishedState;
int m_currentIndex;
};
#endif // PROCESSOR_H
#include "processor.h"
#include <QDebug>
#include <QTimer>
#include <QThread>
Processor::Processor(QObject *parent)
: QObject(parent),
m_machine(new QStateMachine(this)),
m_runningState(new QState(m_machine)),
m_pausedState(new QState(m_machine)),
m_finishedState(new QFinalState(m_machine)),
m_currentIndex(0)
{
// 配置运行状态
connect(m_runningState, &QState::entered, [this]() {
qDebug() << "Entered running state";
processNextItem();
});
// 配置暂停状态
connect(m_pausedState, &QState::entered, [this]() {
qDebug() << "Entered paused state";
});
// 配置暂停状态
// connect(m_finishedState, &QState::entered, [this]() {
// qDebug() << "Entered finished state";
// });
// 配置状态转换
m_runningState->addTransition(this, &Processor::paused, m_pausedState);
m_pausedState->addTransition(this, &Processor::runSig, m_runningState);
m_runningState->addTransition(this, &Processor::finished, m_finishedState);
// 配置状态机
m_machine->setInitialState(m_runningState);
}
bool Processor::isRunning() const
{
return m_machine->isRunning();
}
void Processor::startProcessing()
{
if (!m_machine->isRunning()) {
qDebug() << "Starting processing...";
m_machine->start();
}
}
void Processor::resumeProcessing()
{
++m_currentIndex;
emit runSig();
}
void Processor::processNextItem()
{
if (m_currentIndex >= 30) {
emit finished();
return;
}
emit progressUpdated(m_currentIndex);
if (m_currentIndex == 5 || m_currentIndex == 25) {
qDebug() << "--- Reached pause point ---";
emit paused();
}
else { // 只有非暂停点时继续自动处理
m_currentIndex++;
QThread::msleep(200); //模拟耗时操作
processNextItem();
}
}
单例模式
#ifndef TASKPROCESSOR_H
#define TASKPROCESSOR_H
#include <QObject>
#include <QStateMachine>
#include <QState>
#include <QFinalState>
#include <QQueue>
#include <QMutex>
#include <functional>
class TaskProcessor : public QObject
{
Q_OBJECT
public:
// 单例接口,保证全局唯一
static TaskProcessor& getInstance() {
static TaskProcessor processor;
return processor;
}
// 添加任务到队列
void addTask(const std::function<void()>& task);
// 开始处理任务队列
void startProcessing();
// 暂停任务处理(例如等待外部事件)
void pauseProcessing();
// 恢复任务处理
void resumeProcessing();
signals:
// 任务状态信号,可根据需求扩展
void pausedSig();
void resumeSig();
void taskStarted();
void taskFinished();
void allTasksFinished();
private:
// 构造函数私有,确保单例
explicit TaskProcessor(QObject *parent = nullptr);
Q_DISABLE_COPY(TaskProcessor)
// 内部处理任务队列的方法
void processNextTask();
// 任务队列及同步保护
QQueue<std::function<void()>> m_taskQueue;
QMutex m_mutex;
// 状态机及状态
QStateMachine *m_machine;
QState *m_runningState;
QState *m_pausedState;
QFinalState *m_finishedState;
};
#endif // TASKPROCESSOR_H
#include "processor.h"
#include <QDebug>
#include <QThread>
TaskProcessor::TaskProcessor(QObject *parent)
: QObject(parent),
m_machine(new QStateMachine(this)),
m_runningState(new QState(m_machine)),
m_pausedState(new QState(m_machine)),
m_finishedState(new QFinalState(m_machine))
{
// 配置运行状态:进入运行状态时,尝试处理下一个任务
connect(m_runningState, &QState::entered, this, [this]() {
qDebug() << "Entered running state";
processNextTask();
});
// 配置暂停状态:仅做记录,具体暂停逻辑可通过状态机外部控制
connect(m_pausedState, &QState::entered, this, [this]() {
qDebug() << "Entered paused state";
});
// 状态切换配置:暂停和恢复
m_runningState->addTransition(this, SIGNAL(pausedSig()), m_pausedState);
m_pausedState->addTransition(this, SIGNAL(resumeSig()), m_runningState);
// 当任务全部处理完毕时,切换到结束状态
m_runningState->addTransition(this, SIGNAL(allTasksFinished()), m_finishedState);
// 状态机初始状态设为运行状态
m_machine->setInitialState(m_runningState);
}
void TaskProcessor::addTask(const std::function<void()>& task)
{
QMutexLocker locker(&m_mutex);
m_taskQueue.enqueue(task);
}
void TaskProcessor::startProcessing()
{
if (!m_machine->isRunning()) {
qDebug() << "Starting Task Processing...";
m_machine->start();
}
}
void TaskProcessor::pauseProcessing()
{
// 可以发出信号通知状态机进入暂停状态
qDebug() << "Requesting pause...";
emit pausedSig(); // 此处 SIGNAL 与状态机转换绑定
}
void TaskProcessor::resumeProcessing()
{
// 发出信号恢复处理
qDebug() << "Requesting resume...";
emit resumeSig();
processNextTask();
}
void TaskProcessor::processNextTask()
{
QMutexLocker locker(&m_mutex);
if (m_taskQueue.isEmpty()) {
qDebug() << "All tasks finished.";
emit allTasksFinished();
return;
}
// 取出队列中的下一个任务
std::function<void()> task = m_taskQueue.dequeue();
// 在运行状态下开始任务,发出任务开始信号
emit taskStarted();
qDebug() << "Processing a task...";
// 这里可以在一个独立线程中运行任务,避免阻塞状态机
// 例如:QThread::sleep() 或者使用 QtConcurrent
task();
// 任务执行完成,发出任务结束信号
emit taskFinished();
}