状态机框架提供了创建和执行状态图的一些类.这些概念和表示都是基于Harel状态图中的一些概念和记法.它也是UML状态图表的基础.状态机执行的语义是基于状态图XML(SCXML).
状态图提供了一种图形化的方式来对一个系统建模,从而反映它怎么响应外部触发.这是通过定义系统可能进入的一些状态以及系统怎么从一个状态转换到另一个状态(不同状态之间转变)来实现的.事件驱动系统的一个关键的特征(例如Qt应用程序)就是行为通常不仅取决于上次或当前事件,还取决于在它之前的一些事件.用状态图,这个信息非常容易表达.
状态机框架提供了一套API以及一种执行模型,可有效地将状态图的元素和语义嵌入到Qt应用程序当中.该框架与Qt的元对象系统结合紧密:例如,不同状态之间的转变可由信号触发且状态可配置用于设置QObject的属性和方法.Qt的事件系统用于驱动状态机.
状态机框架中的状态图是分层的.状态可嵌套在另一个状态内.状态机的当前配置包含一些当前活跃的状态.状态机中的一个有效的配置中的所有状态都有一个共同的祖先.
状态机框架中的类
qt提供了这些类来创建事件驱动的状态机.
The
base class of states of a QStateMachine
The
base class of transitions between QAbstractState objects
QObject-specific
transition for Qt events
Final
state
Means
of returning to a previously active substate
Transition
for key events
Transition
for mouse events
Transition
based on a Qt signal
General-purpose
state for QStateMachine
Hierarchical
finite state machine
Represents
a Qt signal event
Holds a
clone of an event associated with a QObject
一个简单的状态机
为了演示状态机API的核心功能,让我们来看一个小例子:一个状态机有三个状态s1,s2和s3.状态机由一个按钮来控制;当点击按钮时,状态机转换到另一个状态.刚开始时,状态机处于状态s1.该状态机的状态图如下所示:
下面代码段显示了创建一个这样的状态机所需的代码.首先,我们创建一个状态机和一些状态:
QStateMachine
machine;
QState
*s1 = new QState();
QState
*s2 = new QState();
QState
*s3 = new QState();
s1->addTransition(button,
SIGNAL(clicked()), s2);
s2->addTransition(button,
SIGNAL(clicked()), s3);
s3->addTransition(button,
SIGNAL(clicked()), s1);
接下来,我们将这些状态加入状态机中并设置它的初始状态:
machine.addState(s1);
machine.addState(s2);
machine.addState(s3);
machine.setInitialState(s1);
最后,我们启动状态机:
状态是异步执行的,例如,它成为你的应用程序事件循环的一部分.
在状态入口和出口做有意义的工作
上面的状态机仅仅从一个状态转换到另一个状态,并没有执行任何操作.函数可用于当进入某个状态时设置某个QObject的一个属性.在下面的代码段中,为每个状态指定了应当赋给QLabel的text属性的值.
s2->assignProperty(label,
"text", "In state s2");
s3->assignProperty(label,
"text", "In state s3");
当进入了这些状态中的任何一个,标签的值就会相应地改变.
当进入某个状态时,就会发出信号.当离开这个状态时,就会发出信号.在下面的代码段中,按钮的showMaximize()槽在进入状态s3时被调用.当退出状态s3时调用showMinimized():
完成的状态机
前面部分定义的状态机从不完成.为了使一个状态机能够完成,它需要拥有一个顶层的最终状态(对象).当状态机进入一个顶层最终状态时,该状态机将会释放信号并停止.
在图中引入一个最终状态,所有你需要做的就是创建一个对象且使用它作为一个或多个转换的目标.
通过对状态进行分组来共享转换
假设我们想让用户能够通过点击Quit揿钮在任何时刻能够退出应用程序.为了完成这个目标,我们需要创建一个最终状态并将其作为与Quit按钮的clicked()信号相关联的转换的目标.我们可以从状态s1,s2,s3中添加一个转换;但是,这看起来像是多余的,并且,我们不得不记住从每个将来新加入的状态添加一个这样的转换.
我们可以通过将状态s1,s2,s3分组取得相同的行为(即点击Quit按钮将退出状态机,无论该状态机处于哪个状态).这是通过创建一个新的顶层状态并使三个原先的