介绍
状态机,就是负责执行各种状态的切换。Qt状态机的使用场景主要针对比较复杂的界面,或者需要切换不同状态的控件
QT中对于状态机框架的介绍:(QT手册中的The State Machine Framework)
状态机框架提供了创建和执行状态图的一些类.这些概念和表示都是基于Harel状态图中的一些概念和记法.它也是UML状态图表的基础.状态机执行的语义是基于状态图XML(SCXML).
状态图提供了一种图形化的方式来对一个系统建模,从而反映它怎么响应外部触发.这是通过定义系统可能进入的一些状态以及系统怎么从一个状态转换到另一个状态(不同状态之间转变)来实现的.事件驱动系统的一个关键的特征(例如Qt应用程序)就是行为通常不仅取决于上次或当前事件,还取决于在它之前的一些事件.用状态图,这个信息非常容易表达.
状态机框架提供了一套API以及一种执行模型,可有效地将状态图的元素和语义嵌入到Qt应用程序当中.该框架与Qt的元对象系统结合紧密:例如,不同状态之间的转变可由信号触发且状态可配置用于设置QObject的属性和方法.Qt的事件系统用于驱动状态机.
状态机框架中的状态图是分层的.状态可嵌套在另一个状态内.状态机的当前配置包含一些当前活跃的状态.状态机中的一个有效的配置中的所有状态都有一个共同的祖先.
qt提供了这些类来创建事件驱动的状态机.状态是单线程异步执行的
class | description |
---|---|
QAbstractState | The base class of states of a QStateMachine(状态机的基类) |
QAbstractTransition | The base class of transitions between QAbstractState objects(状态转换的基类) |
QEventTransition | QObject-specific transition for Qt events(事件转变) |
QFinalState | Final state(终止状态) |
QHistoryState | Means of returning to a previously active substate(历史状态) |
QKeyEventTransition | Transition for key events(按键事件转变) |
QMouseEventTransition | Transition for mouse events(鼠标事件转变) |
QSignalTransition | Transition based on a Qt signal(信号转变) |
QState | General-purpose state for QStateMachine(状态机状态类) |
QStateMachine | Hierarchical finite state machine(提供了分层的有限状态机) |
QStateMachine::SignalEvent | Represents a Qt signal event(截获某一信号时触发) |
QStateMachine::WrappedEvent | Holds 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函数说明
-
QState::assignProperty()函数可用于当进入某个状态时设置某个QObject的一个属性(详细属性名可从Q_PROPERTY中查找)
-
QState::addTransition()函数用于添加与给定发送者对象的给定信号关联的转换,并返回新的QSignalTransition对象
-
当进入某个状态时,就会发出QState::entered()信号.当离开这个状态时,就会发出QState::exited()信号
-
为了使一个状态机能够完成,它需要拥有一个顶层的最终状态(QFinalState对象).当状态机进入一个顶层最终状态时,该状态机将会释放QStateMachine::finished()信号并停止.一个孩子状态可为最终状态(一个QFinalState对象)。当进入最终状态时,父状态发出QState::finished()信号。
-
QState::ChildMode [ExclusiveStates,ParallelStates]
Constant Description QState::ExclusiveStates 子状态是互斥的,必须通过调用QState::setInitialState()来设置初始状态 QState::ParallelStates 子状态是平行的,当父状态被输入时,它的所有子状态将被并行输入;不需要设置初始状态
QHistoryState
Constant | Description |
---|---|
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没有转变目标时为无目标转变,无目标的转变可与其他转变一样的方式被触发;不同之处在于当无目标转变被触发时,它不会造成任何状态的改变。这可以允许你在当状态机处于某个特定状态时,对信号或事件作出响应而不用离开那个状态。