在使用狀態機表述的系統中中存在一個屬性,這個屬性取值都是是互相排斥的,好比電源有打開和關閉,燈有亮和滅,可是不必定只有兩個取值。咱們的理想狀態機不可能只有一個單一的屬性。app
下面咱們舉一個例子,在一個狀態機中存在下面這幾種屬性,每一個屬性都有幾個取值。異步
因此就會有四種狀態,2*2 = 4;若是每一個狀態都是能夠互相轉換的餓,那麼就是4*2 = 8中過渡。函數
若是又添加了一種屬性ui
那麼就是2*2*3=12中狀態,12*2 = 24中過渡,是指數級的增加,並且在添加和移除屬性是,會影響狀態。spa
在此Qt的QState類中有一個枚舉類型線程
第二個平行的狀態集就是爲了解決這個問題。code
#include <QApplication> #include <QState> #include <QStateMachine> #include <QPushButton> #include <QVariant> #include <QFinalState> #include <QLayout> #include <QHistoryState> #include <QLabel> #include <QMessageBox> #include <QtDebug> #include <QAbstractTransition> //Qt的狀態機是層次的,是事件驅動的,使用到了事件循環,那麼就是異步的 int main(int argc, char* argv[]) { QApplication app(argc,argv); QStateMachine sMachine;//一個狀態機對象 QState s;//和fState在同一個層次 QState s0;//開始狀態,空白狀態 QState s1;//3個狀態對象 s1.setChildMode(QState::ParallelStates); s1.setParent(&s); QState s2; s2.setParent(&s); QState s3; s3.setParent(&s); s.setInitialState(&s1);//一組狀態中要指定一組狀態中的初始狀態 QState s11; s11.setChildMode(QState::ExclusiveStates); s11.setParent(&s1); QState s111;//a1 s111.setParent(&s11); QState s112;//a2 s112.setParent(&s11); s11.setInitialState(&s111); QState s12; s12.setChildMode(QState::ExclusiveStates); s12.setParent(&s1); QState s121;//b1 s121.setParent(&s12); QState s122;//b2 s122.setParent(&s12); s12.setInitialState(&s121); QHistoryState sh;//記錄s組狀態被打斷的狀態 sh.setParent(&s); QFinalState fState; QState is;//中斷狀態 QWidget w; QHBoxLayout layout; QPushButton button(QObject::tr("狀態改變")); QPushButton qButton; QPushButton startButton("start"); QPushButton stopButton("stop"); qButton.setText(QObject::tr("退出")); QPushButton iButton; iButton.setText(QObject::tr("打斷")); QPushButton button1("a1,b1"); QPushButton button2("a1,b2"); QPushButton button3("a2,b1"); QPushButton button4("a2,b2"); QLabel showLabel; QLabel showLabel2; QLabel showLabel3; layout.addWidget(&button); layout.addWidget(&qButton); layout.addWidget(&iButton); layout.addWidget(&showLabel); layout.addWidget(&showLabel2); layout.addWidget(&showLabel3); layout.addWidget(&startButton); layout.addWidget(&stopButton); layout.addWidget(&button1); layout.addWidget(&button2); layout.addWidget(&button3); layout.addWidget(&button4); w.setLayout(&layout); QMessageBox box(&w); box.addButton(QMessageBox::Ok); box.setText(QObject::tr("打斷了,如今是is")); box.setIcon(QMessageBox::Information); s0.addTransition(&button,SIGNAL(clicked()),&s); s1.addTransition(&button,SIGNAL(clicked()),&s2);//s1爲這個過渡的始狀態,s2爲末狀態 //八個過渡,但是應爲選擇的是2個屬性,因此是2+2和2*2同樣,可是這樣是線性的 //好比按鈕3被點擊,s111和s122都是activity的同時響應,平行的 s111.addTransition(&button3,SIGNAL(clicked()),&s112);//a1->a2 s111.addTransition(&button4,SIGNAL(clicked()),&s112); s112.addTransition(&button1,SIGNAL(clicked()),&s111);//a2->a1 s112.addTransition(&button2,SIGNAL(clicked()),&s111); s121.addTransition(&button2,SIGNAL(clicked()),&s122);//b1->b2 s121.addTransition(&button4,SIGNAL(clicked()),&s122); s122.addTransition(&button1,SIGNAL(clicked()),&s121);//b2->b1 s122.addTransition(&button3,SIGNAL(clicked()),&s121); s2.addTransition(&button,SIGNAL(clicked()),&s3); s3.addTransition(&button,SIGNAL(clicked()),&s1); //每一個狀態進入時,設置指定對象指定項指定的值 s1.assignProperty(&showLabel,"text","當前:s1"); s2.assignProperty(&showLabel,"text","當前:s2"); s3.assignProperty(&showLabel,"text","當前:s3"); //同時進入,並且這個是原子操做,不會被事件打斷,可是是隊列的,由於狀態機是單線程的 s11.assignProperty(&showLabel,"text","s11"); s12.assignProperty(&showLabel2,"text","s12"); s111.assignProperty(&showLabel,"text","a1"); s112.assignProperty(&showLabel,"text","a2"); s121.assignProperty(&showLabel2,"text","b1"); s122.assignProperty(&showLabel2,"text","b2"); //給每一個狀態添加過渡 s.addTransition(&qButton,SIGNAL(clicked()),&fState);//s -- > finalState,可是在這組內的狀態對於這個過渡能夠覆蓋 //s2.addTransition(&qButton,SIGNAL(clicked()),&s3);//若是添加這一個句,那麼在s2點擊qButton按鈕 //就不會退出,只是轉向了s3 s.addTransition(&iButton,SIGNAL(clicked()),&is); is.addTransition(&sh); QObject::connect(&is,SIGNAL(entered()),&box,SLOT(exec())); //也可能重寫 QAbstractState::onEntry()和QAbstractState::onExit()函數 //在UML的狀態圖中,每一個狀態在進入狀態和離開狀態的時候都會進行相關的操做 //這個能夠經過這兩個信號來解決,也可經過繼承來重寫上述的兩個函數 QObject::connect(&s3,SIGNAL(entered()),&w,SLOT(showMinimized())); QObject::connect(&s3,SIGNAL(exited()),&w,SLOT(showMaximized())); QObject::connect(&sMachine,SIGNAL(finished()),&app,SLOT(quit())); QObject::connect(&startButton,SIGNAL(clicked()),&sMachine,SLOT(start())); QObject::connect(&stopButton,SIGNAL(clicked()),&sMachine,SLOT(stop())); sMachine.addState(&s0); sMachine.addState(&s);//對於狀態機只是添加頂層的狀態 // sMachine.addState(&s1); // sMachine.addState(&s2); // sMachine.addState(&s3); sMachine.addState(&fState); sMachine.addState(&is); //設置狀態機的初始狀態 //sMachine.setInitialState(&s1); sMachine.setInitialState(&s0);//對於狀態機的初始化,只是使用頂層的狀態初始化,因此每一個頂層若是是 //一組狀態,那麼就要指定這組狀態的初始化狀態 w.show(); //狀態機開啓 // sMachine.start(); //能夠經過給狀態分組來實現狀態過渡的共享,好比咱們但願在任何狀態下咱們都可以退出, //那麼這個退出狀態就是比其餘的狀態具備高的狀態層次,那麼咱們就要將其餘的狀態封裝在 //合適的與退出狀態同層次的一個高階的狀態層次中 return app.exec(); }