QState状态机使用详解

介绍

​ 状态机,就是负责执行各种状态的切换。Qt状态机的使用场景主要针对比较复杂的界面,或者需要切换不同状态的控件

QT中对于状态机框架的介绍:(QT手册中的The State Machine Framework)

状态机框架提供了创建和执行状态图的一些类.这些概念和表示都是基于Harel状态图中的一些概念和记法.它也是UML状态图表的基础.状态机执行的语义是基于状态图XML(SCXML).

状态图提供了一种图形化的方式来对一个系统建模,从而反映它怎么响应外部触发.这是通过定义系统可能进入的一些状态以及系统怎么从一个状态转换到另一个状态(不同状态之间转变)来实现的.事件驱动系统的一个关键的特征(例如Qt应用程序)就是行为通常不仅取决于上次或当前事件,还取决于在它之前的一些事件.用状态图,这个信息非常容易表达.

状态机框架提供了一套API以及一种执行模型,可有效地将状态图的元素和语义嵌入到Qt应用程序当中.该框架与Qt的元对象系统结合紧密:例如,不同状态之间的转变可由信号触发且状态可配置用于设置QObject的属性和方法.Qt的事件系统用于驱动状态机.

状态机框架中的状态图是分层的.状态可嵌套在另一个状态内.状态机的当前配置包含一些当前活跃的状态.状态机中的一个有效的配置中的所有状态都有一个共同的祖先.

qt提供了这些类来创建事件驱动的状态机.状态是单线程异步执行的

classdescription
QAbstractStateThe base class of states of a QStateMachine(状态机的基类)
QAbstractTransitionThe base class of transitions between QAbstractState objects(状态转换的基类)
QEventTransitionQObject-specific transition for Qt events(事件转变)
QFinalStateFinal state(终止状态)
QHistoryStateMeans of returning to a previously active substate(历史状态)
QKeyEventTransitionTransition for key events(按键事件转变)
QMouseEventTransitionTransition for mouse events(鼠标事件转变)
QSignalTransitionTransition based on a Qt signal(信号转变)
QStateGeneral-purpose state for QStateMachine(状态机状态类)
QStateMachineHierarchical finite state machine(提供了分层的有限状态机)
QStateMachine::SignalEventRepresents a Qt signal event(截获某一信号时触发)
QStateMachine::WrappedEventHolds a clone of an event associated with a QObject(发生状态转变时触发)
Protected Functions
virtual bool event(QEvent *e) override
virtual void onEntry(QEvent *event) override
virtual void onExit(QEvent *event) override

QState函数说明

  1. QState::assignProperty()函数可用于当进入某个状态时设置某个QObject的一个属性(详细属性名可从Q_PROPERTY中查找)

  2. QState::addTransition()函数用于添加与给定发送者对象的给定信号关联的转换,并返回新的QSignalTransition对象

  3. 当进入某个状态时,就会发出QState::entered()信号.当离开这个状态时,就会发出QState::exited()信号

  4. 为了使一个状态机能够完成,它需要拥有一个顶层的最终状态(QFinalState对象).当状态机进入一个顶层最终状态时,该状态机将会释放QStateMachine::finished()信号并停止.一个孩子状态可为最终状态(一个QFinalState对象)。当进入最终状态时,父状态发出QState::finished()信号。

  5. QState::ChildMode [ExclusiveStates,ParallelStates]

    ConstantDescription
    QState::ExclusiveStates子状态是互斥的,必须通过调用QState::setInitialState()来设置初始状态
    QState::ParallelStates子状态是平行的,当父状态被输入时,它的所有子状态将被并行输入;不需要设置初始状态

QHistoryState

QHistoryState::HistoryType

ConstantDescription
QHistoryState::ShallowHistory默认值,只记录父状态的直接子状态。在这种情况下,以history状态为目标的转换将以父对象上次退出时的直接子状态结束。
QHistoryState::DeepHistory记录嵌套状态。在这种情况下,以历史记录状态作为目标的转换最终将处于父元素上次退出时嵌套最深的子代状态。

函数使用说明

//保存s1的直接子状态
QHistoryState *s1h = new QHistoryState(s1);
QState *s3 = new QState();
s3->assignProperty(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(s1h);
machine.addState(s3);
s1->addTransition(interruptButton, SIGNAL(clicked()), s3);

在进入s3时显示一个信息框,然后通过历史状态立即返回到s1之前的孩子状态中

QStateMachine*s3 = new QStateMachine();
QState* s1 = new QState(QState::ExclusiveStates);//互斥状态
QState* s2 = new QState(QState::ExclusiveStates);
//设置背景色属性
s1->assignProperty(ui.pushButton, "styleSheet", "background-color:rgb(255,0,0)");
s1->assignProperty(ui.pushButton_2, "styleSheet", "background-color:rgb(0,255,0)");

s2->assignProperty(ui.pushButton_2, "styleSheet", "background-color:rgb(255,0,0)");
s2->assignProperty(ui.pushButton, "styleSheet", "background-color:rgb(0,255,0)");

QState* s11 = new QState(s1);
QState* s12 = new QState(s1);
s11->assignProperty(ui.pushButton_4, "styleSheet", "background-color:rgb(255,0,0)");
s11->assignProperty(ui.pushButton_5, "styleSheet", "background-color:rgb(0,255,0)");

s12->assignProperty(ui.pushButton_5, "styleSheet", "background-color:rgb(255,0,0)");
s12->assignProperty(ui.pushButton_4, "styleSheet", "background-color:rgb(0,255,0)");
//当this发出sig_pushbutton_4()信号时,状态由s11切换到s12
s11->addTransition(this, SIGNAL(sig_pushbutton_4()), s12);
//当this发出sig_pushbutton_5()信号时,状态由s12切换到s11
s12->addTransition(this, SIGNAL(sig_pushbutton_5()), s11);
//当this发出sig_pushbutton()信号时,状态由s1切换到s2
s1->addTransition(this, SIGNAL(sig_pushbutton()), s2);
//当this发出sig_pushbutton_2()信号时,状态由s2切换到s1
s2->addTransition(this, SIGNAL(sig_pushbutton_2()), s1);
//将状态添加到状态机
s3->addState(s1);
s3->addState(s2);
s1->setInitialState(s11);
//由于状态为互斥状态,此处应设置初始状态
s3->setInitialState(s1);
//状态机启动
s3->start();

状态机状态转换:s3为状态机,s1、s2为顶级状态,s11、s12都为继承于s1的次级状态,所以当只有s1处于active状态时,s11、s12才会处于active状态

	QFinalState *state1 = new QFinalState(s1);
	s12->addTransition(this, SIGNAL(sig_pushbutton_5()), state1);
	s1->addTransition(s1, SIGNAL(finished()), s2);

实例化一个继承于s1的终止状态state1,当this发送sig_pushbutton_5()信号时,状态从s12切换到state1,此时s1会发出finished()

当addTransition没有转变目标时为无目标转变,无目标的转变可与其他转变一样的方式被触发;不同之处在于当无目标转变被触发时,它不会造成任何状态的改变。这可以允许你在当状态机处于某个特定状态时,对信号或事件作出响应而不用离开那个状态。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的状态分组示例代码,用于控制一个灯的开关: ```python from PyQt5 import QtCore class LightStateMachine: class OffState(QtCore.QState): def onEntry(self, event): print("灯已关闭") class OnState(QtCore.QState): def onEntry(self, event): print("灯已开启") def __init__(self): self.machine = QtCore.QStateMachine() self.off_state = self.OffState() self.on_state = self.OnState() self.off_state.addTransition(self.off_state.transitOn) self.on_state.addTransition(self.on_state.transitOff) self.machine.addState(self.off_state) self.machine.addState(self.on_state) self.machine.setInitialState(self.off_state) self.machine.start() def turnOn(self): self.machine.postEvent(self.on_state.transitOn) def turnOff(self): self.machine.postEvent(self.off_state.transitOff) ``` 在这个示例代码中,我们定义了两个状态:打开状态和关闭状态。每个状态都是一个 `QState` 的子类,并实现了 `onEntry` 方法,在进入状态时触发。我们还定义了两个事件:`transitOn` 和 `transitOff`,它们用于触发状态转换。 在 `__init__` 方法中,我们创建了一个状态,并将两个状态添加到状态中。我们还将关闭状态设置为初始状态,并启动状态。 最后,我们定义了两个方法 `turnOn` 和 `turnOff`,用于触发状态转换。它们会将相应的事件发送到状态中。 通过这个状态分组示例代码,我们可以控制一个灯的开关状态,并在状态转换时输出一些信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值