日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt状态机框架介绍(一)

發布時間:2025/1/21 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt状态机框架介绍(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

狀態機,簡寫為FSM(Finite State Machine),狀態機由狀態寄存器和組合邏輯電路構成,能夠根據控制信號按照預先設定的狀態進行狀態轉移,是協調相關信號動作、完成特定操作的控制中心。
簡單來說,狀態機,就是負責執行各種狀態的切換。Qt狀態機的使用場景主要針對比較復雜的界面,或者需要切換不同狀態的控件,比如三態按鈕,每個狀態對應不同的樣式,如果自己做狀態管理,那就比較麻煩了。

而狀態機就是解決這種問題的,Qt中的狀態機框架為我們提供了很多的API和類,使我們能更容易的在自己的應用程序中集成狀態動畫。這個框架是和Qt的元對象系統機密結合在一起的。比如,各個狀態之間的轉換是通過信號觸發的,狀態可被配置為用來設置QObject對象的屬性以及調用其方法。可以說Qt中的狀態機就是通過Qt自身的事件系統來驅動的。

狀態機框架中的狀態圖是分層的。狀態可以嵌套在其他狀態中,狀態機的當前配置由當前活動的狀態集組成。狀態機有效配置中的所有狀態都有一個共同的祖先。

狀態機框架中的類

以下類由Qt提供,用于創建事件驅動的狀態機。

一個簡單的示例

接下來直接通過一個簡單的示例來了解Qt狀態機的工作方式。

最基礎的Qt狀態機使用流程如下:

  • 創建一個狀態機QStateMachine和需要的狀態QState
  • 使用QState::addTransition() 函數為這些狀態之間添加過渡
  • 將狀態添加到狀態機進行管理,并為狀態機設置一個初始狀態
  • 啟動狀態機

效果圖:


這里btn2有三種狀態,分別顯示在不同的位置,通過點擊Btn1進行狀態的切換。

其狀態圖如下:

接下來看看代碼:

#include <QWidget> #include <QState> #include <QStateMachine>namespace Ui { class Widget; }class Widget : public QWidget {Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();private slots:void onOutputMessage();private:Ui::Widget *ui;QStateMachine * m_pStateMachine = nullptr;QState * m_pState1 = nullptr;QState * m_pState2 = nullptr;QState * m_pState3 = nullptr; }; #include "widget.h" #include "ui_widget.h" #include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);m_pStateMachine = new QStateMachine(this);m_pState1 = new QState();m_pState2 = new QState();m_pState3 = new QState();m_pState1->assignProperty(ui->btn2,"pos",QPoint(20,40));m_pState2->assignProperty(ui->btn2,"pos",QPoint(80,40));m_pState3->assignProperty(ui->btn2,"pos",QPoint(120,40));m_pState1->addTransition(ui->btn1,SIGNAL(clicked()),m_pState2);m_pState2->addTransition(ui->btn1,SIGNAL(clicked()),m_pState3);m_pState3->addTransition(ui->btn1,SIGNAL(clicked()),m_pState1);m_pStateMachine->addState(m_pState1);m_pStateMachine->addState(m_pState2);m_pStateMachine->addState(m_pState3);m_pStateMachine->setInitialState(m_pState1);m_pStateMachine->setInitialState(m_pState1);m_pStateMachine->start(); }Widget::~Widget() {delete ui; }

這樣狀態機就開始異步的運行了,也就是說,它成為了我們應用程序事件循環的一部分。這也對應了我們上面說的,Qt的狀態機是通過Qt自身的事件機制來驅動的。

狀態轉換時操作QObject對象

使用QState::assignProperty() 函數當進入某個狀態時讓其去修改某個QObject對象的屬性。也就是上面使用的m_pState1->assignProperty(ui->btn2,"pos",QPoint(20,40)); 執行該狀態時,改變Btn2的位置屬性。

除了操作QObject對象的屬性外,我們還能通過狀態的轉換來調用QObject對象的函數。這是通過使用狀態轉換時發出的信號完成的。其中,當進入某個狀態時會發出QState::enterd() 信號,當退出某個狀態時會發出QState::exited() 信號。

connect(m_pState3,&QState::entered,this,[=](){qDebug() << __FUNCTION__ << "state3 entered..";});connect(m_pState3,&QState::exited,this,[=](){qDebug() << __FUNCTION__ << "state3 exited..";});

當進入和離開m_pState3狀態時,將會輸出響應的日志。

狀態機結束

以上的示例狀態機是永遠不會停止的,每次點擊按鈕會一直循環切換不同狀態,那現在如果要停止狀態機該怎么辦呢。

為了使一個狀態機在某種條件下結束,我們需要創建一個頂層的final 狀態(QFinalState object) 。當狀態機進入一個頂層的final 狀態時,會發出finished() 信號后結束。所以,我們只需要為上面的狀態圖引入一個final 狀態,并把它設置為某個過渡的目標狀態即可。這樣當狀態機在某種條件下轉換到該狀態時,整個狀態機結束。

如果我們想讓用戶隨時通過點擊退出按鈕來退出整個應用程序。為了實現這個需求,我們需要創建一個final狀態并使他成為和按鈕的clicked()信號相關聯的那個過渡的目標狀態。有兩種方案:

  • 方法一:為狀態s1,s2,s3分別添加一個到final狀態的過渡,但這看上去有點多余,代碼臃腫,并且不利于將來的擴張。
  • 方法二:將狀態s1,s2,s3分成一組。我們通過創建一個新的頂層狀態并使s1,s2,s3成為其孩子來完成。下面是這種方法所對應的狀態轉換圖:

上面的三個狀態被重命名為s11,s12,s13以此來表明它們是s1的孩子。子狀態會隱式的繼承父狀態的過渡。這意味著我們目前可以只添加一個s1到final狀態s2的過渡即可,s11,s12,s13會繼承這個過渡,從而無論在什么狀態均可退出應用程序。并且,將來新添加到s1的新的子狀態也會自動繼承這個過渡。

所謂的分組,就是只需在創建狀態時為其指定一個合適的父狀態即可。當然,還需要為這組狀態指定一個初始狀態,即當s1是某個過渡的目標狀態時,狀態機應該進入哪個子狀態。實現代碼如下:

#include <QWidget> #include <QState> #include <QStateMachine> #include <QFinalState>namespace Ui { class Widget; }class Widget : public QWidget {Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();private slots:void onOutputMessage();private:Ui::Widget *ui;QStateMachine * m_pStateMachine = nullptr;QState * m_pState1 = nullptr;QState * m_pState2 = nullptr;QState * m_pState3 = nullptr;QState * m_pStateParent = nullptr;QFinalState * m_pFinalState = nullptr; }; #include "widget.h" #include "ui_widget.h" #include <QDebug>Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);m_pStateMachine = new QStateMachine(this);m_pStateParent = new QState();m_pState1 = new QState(m_pStateParent);m_pState2 = new QState(m_pStateParent);m_pState3 = new QState(m_pStateParent);m_pState1->assignProperty(ui->btn2,"pos",QPoint(20,40));m_pState2->assignProperty(ui->btn2,"pos",QPoint(80,40));m_pState3->assignProperty(ui->btn2,"pos",QPoint(120,40));m_pState1->addTransition(ui->btn1,SIGNAL(clicked()),m_pState2);m_pState2->addTransition(ui->btn1,SIGNAL(clicked()),m_pState3);m_pState3->addTransition(ui->btn1,SIGNAL(clicked()),m_pState1);m_pStateParent->setInitialState(m_pState1);m_pFinalState = new QFinalState();//當點擊Btn3時,停止狀態機m_pStateParent->addTransition(ui->btn3,SIGNAL(clicked()),m_pFinalState);m_pStateMachine->addState(m_pStateParent);m_pStateMachine->addState(m_pFinalState);m_pStateMachine->setInitialState(m_pStateParent);connect(m_pState3,&QState::entered,this,[=](){qDebug() << __FUNCTION__ << "state3 entered..";});connect(m_pState3,&QState::exited,this,[=](){qDebug() << __FUNCTION__ << "state3 exited..";});connect(m_pStateMachine,&QStateMachine::finished,this,[=](){qDebug() << __FUNCTION__ ;});m_pStateMachine->start(); }Widget::~Widget() {delete ui; }

效果圖如下:


以上示例,當點擊Btn3時,停止狀態機。這時候再點擊Btn1就不會再有狀態切換。

以上是基礎的狀態機使用演示。

參考地址:https://doc.qt.io/qt-5/statemachine-api.html#?tdsourcetag=s_pctim_aiomsg

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Qt状态机框架介绍(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。