网站首页 > 编程文章 正文
前言
上一篇博客中已经介绍了Qt状态机的基础概念和用法,接下来继续介绍Qt状态机的使用。
历史状态的保存和恢复
前一个示例中,我们通过一个按钮中断状态机,在此基础上,如果我们中断状态机过后想再次回到之前停下来的地方,这时候就需要使用到历史状态。
历史状态是一个假想的状态,它表示了父状态上次退出时的子状态。
历史状态通常创建为想要保存的那个状态的子状态。这样在程序运行时,当状态机检测到这种状态的存在就会在父状态退出时自动记录当前的子状态。连接到历史状态的过渡实际上就是连接到状态机上次保存的子状态,状态机会自动的将过渡前移到正在的子状态。下面是执行流程:
先看一下效果图:
代码如下:
#include <QWidget>
#include <QState>
#include <QStateMachine>
#include <QFinalState>
#include <QHistoryState>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void onOutputMessage();
private:
Ui::Widget *ui;
QStateMachine * m_pStateMachine = nullptr;
QState * m_pState1 = nullptr;
QState * m_pState2 = nullptr;
QState * m_pState3 = nullptr;
QState * m_pStateParent = nullptr;
QFinalState * m_pFinalState = nullptr;
QHistoryState * m_pHistoryState = nullptr;
};
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
m_pStateMachine = new QStateMachine(this);
m_pStateParent = new QState();
m_pState1 = new QState(m_pStateParent);
m_pState2 = new QState(m_pStateParent);
m_pState3 = new QState(m_pStateParent);
m_pStateParent->assignProperty(ui->label, "text", "In s1");
m_pState1->assignProperty(ui->btn2,"pos",QPoint(20,40));
m_pState2->assignProperty(ui->btn2,"pos",QPoint(80,40));
m_pState3->assignProperty(ui->btn2,"pos",QPoint(120,40));
m_pState1->addTransition(ui->btn1,SIGNAL(clicked()),m_pState2);
m_pState2->addTransition(ui->btn1,SIGNAL(clicked()),m_pState3);
m_pState3->addTransition(ui->btn1,SIGNAL(clicked()),m_pState1);
m_pStateParent->setInitialState(m_pState1);
m_pFinalState = new QFinalState();
m_pStateParent->addTransition(ui->btn3,SIGNAL(clicked()),m_pFinalState);
m_pStateMachine->addState(m_pStateParent);
m_pStateMachine->addState(m_pFinalState);
m_pStateMachine->setInitialState(m_pStateParent);
m_pHistoryState = new QHistoryState(m_pStateParent);
QState *s3 = new QState();
s3->assignProperty(ui->label, "text", "In s3");
QMessageBox *mbox = new QMessageBox(this);
mbox->addButton(QMessageBox::Ok);
mbox->setText("Interrupted!");
mbox->setIcon(QMessageBox::Information);
QObject::connect(s3, SIGNAL(entered()), mbox, SLOT(exec()));
s3->addTransition(m_pHistoryState);
m_pStateMachine->addState(s3);
m_pStateParent->addTransition(ui->btn2, SIGNAL(clicked()), s3);
m_pStateMachine->start();
}
Widget::~Widget()
{
delete ui;
}
使用并行状态来避免过多的状态组合
当需要同步执行多个状态时,可以将状态机设置成并行状态组,进入到并行状态后,所有子状态都会同时开始运行,每个子状态的过渡都会正常执行。但是,每一个子状态都有可能退出父状态,如果这样,父状态和它所有的子状态都会结束。
在Qt状态机框架的并行机制里有一个交错语义。所有的并行操作都是在一个事件处理中独立的、原子的被执行,所以没有事件能打断并行操作。但是,事件仍然是被顺序的处理的,因为状态机本身是单线程的。举个例子,如果有两个过渡退出同一个并行状态组,并且它们的触发条件同时被满足。在这种情况下,第二个被处理的退出事件将没有任何实际的反应,因为第一个事件已经导致了状态机从并行状态中结束。
并行状态示例:
QState *s1 = new QState(QState::ParallelStates);
// s11 and s12 will be entered in parallel
QState *s11 = new QState(s1);
QState *s12 = new QState(s1);
检测组合状态的结束
子状态可以是一个final状态;当进入一个final子状态时,父状态会发出finished() 信号。下图显示了一个组合状态s1在做了一系列的处理后进入了一个final状态:
当s1进入一个final子状态时,s1会自动发出finished() 信号。我们使用一个 信号过渡 来触发一个状态转换:
s1->addTransition(s1, SIGNAL(finished()), s2);
在组合状态中使用final状态对应想隐藏组合状态的内部细节来说是非常有用的。也就是说,对于外部世界来说,只需要进入这个状态,然后等待这个状态的完成信号即可。这对于构建复杂的状态机来说是一种强有力的的封装和抽象机制。但是,对于并行状态组来说,finishe()信号只有在所有的子状态都进入final状态时才会发出。
无目标状态的过渡
一个Transition并不是一定要有一个目标状态,并且没有目标状态的过渡也可以像其他过渡一样被触发。区别是当一个没有目标状态的过渡被触发时,不会导致任何状态的改变。这运行你在状态机进入某个状态时响应一个信号或事件而不必离开那个状态。
示例:
m_pStateMachine = new QStateMachine(this);
m_pState1 = new QState();
QSignalTransition *trans = new QSignalTransition(ui->btn1, SIGNAL(clicked()));
m_pState1->addTransition(trans);
m_pStateMachine->addState(m_pState1);
m_pStateMachine->setInitialState(m_pState1);
QMessageBox *mbox = new QMessageBox(this);
mbox->addButton(QMessageBox::Ok);
mbox->setText("Interrupted!");
mbox->setIcon(QMessageBox::Information);
QObject::connect(trans, SIGNAL(triggered()), mbox, SLOT(exec()));
m_pStateMachine->start();
当每次点击按钮时,都会弹出消息框,但是状态会一直停留在m_pState1,如果显示的把状态机的状态设置为s1,s1状态会结束,然后重新进入该状态。
点击领取Qt学习资料+视频教程~「链接」
- 上一篇: Qt编写安防视频监控系统9-自动隐藏光标
- 下一篇: Qt开发经验总结之武林秘籍(qt开发程序)
猜你喜欢
- 2024-09-11 Qt开发-文本编辑器中的数据存取(qt文本编辑器代码)
- 2024-09-11 Qt数据库应用15-通用数据库同步(qt的数据库操作)
- 2024-09-11 开源|一个基于QT设计串口调试工具
- 2024-09-11 第23天 | 28天学会PyQt5,多行文本框
- 2024-09-11 PyQt: QAbstractButton开关按钮与互斥的用法
- 2024-09-11 第6篇 基础(六)实现Qt文本编辑功能
- 2024-09-11 实战PyQt5: 003-PyQt的信号和槽机制简介
- 2024-09-11 Qt开发经验小技巧181-185(qt软件开发)
- 2024-09-11 Qt开发经验总结之武林秘籍(qt开发程序)
- 2024-09-11 Qt编写安防视频监控系统9-自动隐藏光标
你 发表评论:
欢迎- 05-142014年最流行前端开发框架对比评测
- 05-14七爪源码:如何使用 Next.js 构建 Shopify 店面
- 05-14Web 前端怎样入门?
- 05-14我为什么不建议你使用框架
- 05-14推荐几个好用的React UI 框架
- 05-14PDFsharp:强大的 .NET 跨平台 PDF 处理库
- 05-14一组开源免费的Web动画图标,荐给需要的设计师和程序员
- 05-14salesforce 零基础学习(二十九)Record Types简单介绍
- 最近发表
- 标签列表
-
- spire.doc (59)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- sqljdbc4.jar下载 (56)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- 苹果ios字体下载 (56)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)