Qt狀態機學習3

                      在使用狀態機表述的系統中中存在一個屬性,這個屬性取值都是是互相排斥的,好比電源有打開和關閉,燈有亮和滅,可是不必定只有兩個取值。咱們的理想狀態機不可能只有一個單一的屬性。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();
}
                     
相關文章
相關標籤/搜索