咱們在使用狀態機時,可能在執行一組狀態的過程當中跳轉到一個新狀態執行完任務後還須要跳轉到原來執行被打斷的地方,Qt的狀態機框架爲咱們提供了QHistoryState類。這個類只要將它加入到這組狀態中,它就會記住固然執行到的這組狀態中的哪個。app
#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 s1;//3個狀態對象 s1.setParent(&s); QState s2; s2.setParent(&s); QState s3; s3.setParent(&s); s.setInitialState(&s1);//一組狀態中要指定一組狀態中的初始狀態 QHistoryState sh;//記錄s組狀態被打斷的狀態 sh.setParent(&s); QFinalState fState; QState is;//中斷狀態 QWidget w; QHBoxLayout layout; QPushButton button; QPushButton qButton; qButton.setText(QObject::tr("退出")); QPushButton iButton; iButton.setText(QObject::tr("打斷")); QLabel showLabel(QObject::tr("sssssss")); layout.addWidget(&button); layout.addWidget(&qButton); layout.addWidget(&iButton); layout.addWidget(&showLabel); w.setLayout(&layout); QMessageBox box(&w); box.addButton(QMessageBox::Ok); box.setText(QObject::tr("打斷了,如今是is")); box.setIcon(QMessageBox::Information); s1.addTransition(&button,SIGNAL(clicked()),&s2);//s1爲這個過渡的始狀態,s2爲末狀態 s2.addTransition(&button,SIGNAL(clicked()),&s3); s3.addTransition(&button,SIGNAL(clicked()),&s1); //每一個狀態進入時,設置指定對象指定項指定的值 s1.assignProperty(&button,"text","s1"); s2.assignProperty(&button,"text","s2"); s3.assignProperty(&button,"text","s3"); //給每一個狀態添加過渡 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())); sMachine.addState(&s);//對於狀態機只是添加頂層的狀態 // sMachine.addState(&s1); // sMachine.addState(&s2); // sMachine.addState(&s3); sMachine.addState(&fState); sMachine.addState(&is); //設置狀態機的初始狀態 //sMachine.setInitialState(&s1); sMachine.setInitialState(&s);//對於狀態機的初始化,只是使用頂層的狀態初始化,因此每一個頂層若是是 //一組狀態,那麼就要指定這組狀態的初始化狀態 w.show(); //狀態機開啓 sMachine.start(); //能夠經過給狀態分組來實現狀態過渡的共享,好比咱們但願在任何狀態下咱們都可以退出, //那麼這個退出狀態就是比其餘的狀態具備高的狀態層次,那麼咱們就要將其餘的狀態封裝在 //合適的與退出狀態同層次的一個高階的狀態層次中 return app.exec(); }上面的這個例子,在s狀態組中添加了一個 QHistoryState對象記錄當前的執行到的狀態。在咱們點擊中斷按鈕後,咱們從一個s的子狀態跳轉到is狀態,而後在跳轉到s被打斷的狀態。
以下圖所示:框架
此時咱們點擊s2會跳轉到s3,進入s3會觸發異步
QObject::connect(&s3,SIGNAL(entered()),&w,SLOT(showMinimized()));這個信號和槽,窗體會最小化
如今在點擊打斷按鈕,從s3跳轉到is狀態會觸發函數
QObject::connect(&s3,SIGNAL(exited()),&w,SLOT(showMaximized()));因此會最大化,而後彈出一個阻塞的QMessagebox,當咱們點擊ok,is會轉到記錄的那個轉出狀態也就是s3,又觸發了
QObject::connect(&s3,SIGNAL(entered()),&w,SLOT(showMinimized()));因此會最小化。