Qt---狀態機框架QState

QState是Qt狀態機框架(Qt State Machine Framework)的核心類,用于建模離散狀態以及狀態間的轉換邏輯,廣泛應用于UI交互流程、設備狀態管理、工作流控制等場景。它基于UML狀態圖規范設計,支持層次化狀態、并行狀態、歷史狀態等高級特性,能夠簡化復雜狀態邏輯的實現。

一、核心定位與繼承關系

QState繼承自QAbstractState(抽象狀態基類),而QAbstractState又繼承自QObject,因此QState具備Qt對象模型的所有特性(如信號槽、元對象系統、父子關系管理)。其核心作用是:

  • 封裝一個離散狀態的l行為(進入/退出時的動作);
  • 管理狀態間的轉換規則(QAbstractTransition);
  • 支持子狀態嵌套,構建層次化狀態機;
  • QStateMachine配合,實現狀態的自動切換。

狀態機的基本構成包括:

  • 狀態(State):如QStateQParallelState(并行狀態)、QHistoryState(歷史狀態);
  • 轉換(Transition):如QSignalTransition(信號觸發)、QEventTransition(事件觸發);
  • 事件(Event):觸發狀態轉換的信號、Qt事件或自定義事件;
  • 狀態機(State Machine)QStateMachine,負責調度狀態切換與事件處理。

二、基礎用法:狀態創建與轉換

1. 狀態的創建與添加

通過QStateMachine管理狀態,需先創建狀態實例并添加到狀態機中:

#include <QStateMachine>
#include <QState>
#include <QPushButton>QStateMachine *machine = new QStateMachine;// 創建狀態
QState *s1 = new QState(machine);  // 直接指定父對象為狀態機
QState *s2 = new QState;
machine->addState(s2);  // 或通過addState()添加// 設置初始狀態(狀態機啟動時進入的第一個狀態)
machine->setInitialState(s1);
2. 狀態轉換的定義

狀態轉換(QAbstractTransition)是狀態切換的規則,需指定“觸發條件”和“目標狀態”。QState通過addTransition()方法添加轉換,常用轉換類型包括:

(1)信號觸發轉換(QSignalTransition)

最常用的轉換類型,當特定信號發射時觸發狀態切換:

QPushButton *btn = new QPushButton("Next");// 當btn發射clicked()信號時,從s1轉換到s2
s1->addTransition(btn, &QPushButton::clicked, s2);// 進階:轉換可攜帶動作(通過onTransition()信號)
QSignalTransition *trans = s1->addTransition(btn, &QPushButton::clicked, s2);
connect(trans, &QSignalTransition::onTransition, [](){qDebug() << "從s1切換到s2";  // 轉換過程中執行的動作
});
(2)事件觸發轉換(QEventTransition)

基于Qt事件(如QKeyEventQMouseEvent)觸發轉換:

#include <QEventTransition>// 當s1收到QEvent::KeyPress事件時,轉換到s2
QEventTransition *keyTrans = new QEventTransition(btn, QEvent::KeyPress);
keyTrans->setTargetState(s2);
s1->addTransition(keyTrans);
(3)守衛條件(Guard)

轉換可設置守衛條件(布爾函數),僅當條件為true時才執行轉換:

// 定義守衛函數(返回bool)
bool canTransition() {return someCondition;  // 例如:檢查輸入是否合法
}// 為轉換設置守衛
trans->setGuard(canTransition);  // 僅當canTransition()為true時,轉換才生效

三、狀態行為:進入與退出動作

QState在進入(entered)和退出(exited)時會發射對應信號,可通過信號槽機制綁定狀態切換時的動作。此外,還可通過onEntry()onExit()方法直接設置動作函數。

1. 信號綁定方式
// 進入s1時執行動作
connect(s1, &QState::entered, [](){qDebug() << "進入狀態s1";// 例如:更新UI顯示、啟動定時器
});// 退出s1時執行動作
connect(s1, &QState::exited, [](){qDebug() << "退出狀態s1";// 例如:停止定時器、保存臨時數據
});
2. 動作函數方式

通過assignProperty()可在進入狀態時自動為對象設置屬性,簡化UI狀態管理:

QPushButton *btn = new QPushButton("Click me");// 進入s1時,將btn的text屬性設為"狀態1",enabled設為true
s1->assignProperty(btn, "text", "狀態1");
s1->assignProperty(btn, "enabled", true);// 進入s2時,更新btn屬性
s2->assignProperty(btn, "text", "狀態2");
s2->assignProperty(btn, "enabled", false);

當狀態激活時,assignProperty()設置的屬性會自動應用到目標對象,退出狀態時不會自動恢復(需手動在exited信號中處理)。

四、層次化狀態:父狀態與子狀態

QState支持嵌套子狀態,形成層次化結構(父狀態包含子狀態),這是實現復雜狀態邏輯的核心特性。

1. 子狀態的添加與初始子狀態
// 創建父狀態
QState *parentState = new QState;// 創建子狀態(指定父狀態)
QState *child1 = new QState(parentState);
QState *child2 = new QState(parentState);// 設置父狀態的初始子狀態(進入父狀態時自動進入該子狀態)
parentState->setInitialState(child1);
2. 層次化狀態的行為規則
  • 進入父狀態:先執行父狀態的entered動作,再進入其初始子狀態(執行子狀態的entered動作);
  • 退出父狀態:先退出當前活躍的子狀態(執行子狀態的exited動作),再執行父狀態的exited動作;
  • 子狀態轉換限制:子狀態的轉換默認只能在同一父狀態的子狀態間進行,若需轉換到外部狀態,需顯式指定目標。

示例:播放器的“播放中”狀態(父狀態)包含“正常播放”和“快進”子狀態:

QState *playing = new QState;  // 父狀態:播放中
QState *normalPlay = new QState(playing);  // 子狀態:正常播放
QState *fastForward = new QState(playing); // 子狀態:快進playing->setInitialState(normalPlay);// 子狀態間轉換:正常播放 → 快進(按快進鍵)
normalPlay->addTransition(fastForwardBtn, &QPushButton::clicked, fastForward);
// 子狀態轉換到外部狀態:任何子狀態下按停止鍵 → 停止狀態
playing->addTransition(stopBtn, &QPushButton::clicked, stopped);

五、特殊狀態類型

1. 并行狀態(QParallelState)

用于建模同時活躍的多個狀態(如設備同時處于“聯網”和“充電”狀態)。QParallelStateQState的子類,其所有子狀態會同時進入和退出。

#include <QParallelState>QParallelState *parallel = new QParallelState;// 兩個并行子狀態
QState *networkState = new QState(parallel);  // 網絡狀態
QState *powerState = new QState(parallel);    // 電源狀態// 進入parallel時,networkState和powerState同時激活
machine->setInitialState(parallel);

并行狀態的退出規則:所有子狀態退出后,并行狀態才會退出。

2. 歷史狀態(QHistoryState)

用于保存父狀態中最后活躍的子狀態,當父狀態再次進入時,自動恢復到該子狀態(避免重復初始化)。分為兩種類型:

  • 淺歷史(默認):僅恢復直接子狀態的歷史;
  • 深歷史:遞歸恢復所有嵌套子狀態的歷史(通過setDeepHistory(true)啟用)。
#include <QHistoryState>QState *parent = new QState;
QState *child1 = new QState(parent);
QState *child2 = new QState(parent);
parent->setInitialState(child1);// 創建歷史狀態(作為parent的子狀態)
QHistoryState *history = new QHistoryState(parent);
// 啟用深歷史(可選)
history->setDeepHistory(true);// 從外部狀態轉換到history時,恢復parent的最后活躍子狀態
externalState->addTransition(backBtn, &QPushButton::clicked, history);

六、狀態機的運行與生命周期

1. 狀態機的啟動與停止
// 啟動狀態機(開始處理事件并進入初始狀態)
machine->start();// 停止狀態機(退出當前狀態,暫停事件處理)
machine->stop();

狀態機啟動后,會觸發初始狀態的entered信號,并開始監聽事件以驅動轉換。

2. 狀態機的完成與終止

當狀態機進入“終止狀態”(QFinalState)時,會發射finished()信號并停止運行:

#include <QFinalState>QFinalState *final = new QFinalState(machine);// 從s2轉換到終止狀態
s2->addTransition(quitBtn, &QPushButton::clicked, final);// 狀態機完成時退出程序
connect(machine, &QStateMachine::finished, qApp, &QApplication::quit);

七、高級特性與底層機制

1. 事件優先級與處理順序

狀態機的事件處理遵循以下規則:

  • 子狀態的事件處理器優先于父狀態;
  • 同一狀態的多個轉換按添加順序檢查(守衛條件先滿足者觸發);
  • 并行狀態的子狀態獨立處理事件,互不干擾。
2. 自定義轉換與事件

通過繼承QAbstractTransition可實現自定義轉換邏輯,通過QEvent子類可定義自定義事件:

// 自定義事件
class MyEvent : public QEvent {
public:static const QEvent::Type Type = static_cast<QEvent::Type>(QEvent::User + 1);MyEvent() : QEvent(Type) {}
};// 自定義轉換(監聽MyEvent)
class MyTransition : public QAbstractTransition {
protected:bool eventTest(QEvent *e) override {return e->type() == MyEvent::Type;  // 僅響應MyEvent}void onTransition(QEvent *) override {// 轉換動作}
};// 使用自定義轉換
MyTransition *trans = new MyTransition;
trans->setTargetState(s2);
s1->addTransition(trans);
3. 調試與狀態監控

Qt提供QStateMachine::setDebuggingEnabled(true)開啟調試日志,輸出狀態轉換過程:

machine->setDebuggingEnabled(true);  // 控制臺會打印狀態切換日志

也可通過QState::active()方法實時檢查狀態是否活躍:

if (s1->active()) {qDebug() << "當前處于s1狀態";
}

八、常見問題

  1. 狀態轉換循環:避免無守衛條件的循環轉換(如s1→s2→s1),可能導致狀態機無限切換;
  2. 子狀態與父狀態的信號沖突:子狀態的entered信號會在父狀態之后觸發,需注意動作執行順序;
  3. 并行狀態的同步:并行子狀態的轉換獨立,若需同步退出,可統一轉換到同一個終止狀態;
  4. 歷史狀態的濫用:僅在需要恢復狀態時使用,過度使用會增加狀態機復雜度;
  5. 性能考量:復雜狀態機(>100個狀態)需避免頻繁轉換,可通過合并狀態減少開銷。

QState作為Qt狀態機框架的核心,通過封裝狀態行為、轉換規則和層次化結構,大幅簡化了復雜狀態邏輯的實現。其特性包括:支持信號/事件觸發的轉換、狀態進入/退出動作、屬性自動賦值、層次化與并行狀態、歷史狀態恢復等。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95726.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95726.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95726.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GitHub 熱榜項目 - 日榜(2025-09-02)

GitHub 熱榜項目 - 日榜(2025-09-02) 生成于&#xff1a;2025-09-02 統計摘要 共發現熱門項目&#xff1a;14 個 榜單類型&#xff1a;日榜 本期熱點趨勢總結 本期GitHub熱榜呈現AI Agent生態爆發趨勢&#xff0c;Koog、Activepieces等項目推動多平臺智能體開發框架成熟。語…

華為衛星對星引導技術深度解析:原理、實現與開源替代方案

利號&#xff1a;CNXXXXXX 涉及多傳感器融合/自適應波束成形/軌道預測算法一、技術原理剖析&#xff1a;衛星間高精度指向的核心挑戰在低軌衛星&#xff08;LEO&#xff09;星座中&#xff0c;衛星間鏈路&#xff08;ISL&#xff09;的建立面臨三大技術難題&#xff1a;1. 動力…

水下管道巡檢機器人結構設cad+三維圖+設計說明書

目 錄 1 緒論 1 1.1 選題的背景及意義 1 1.2 水下管道巡檢機器人的分類 2 1.2.1 管道巡檢技術的分類 2 1.2.2管道巡檢機器人的分類 2 1.3 研究的現狀 3 1.3.1 國內的研究現狀 3 1.3.2 國外的研究現狀 4 1.4 水下管道巡檢機器人的發展趨勢 5 1.…

[從零開始面試算法] (11/100) LeetCode 226. 反轉二叉樹:遞歸的“鏡像”魔法

引言 歡迎來到本系列的第十一篇&#xff01;在我們通過“最大深度”問題初步領略了樹的遞歸之美后&#xff0c;今天我們將面對一個更能體現遞歸“分治”思想的經典問題——LeetCode 226. 反轉二叉樹。 這道題在面試界的地位非同凡響&#xff0c;它因 Homebrew 的作者 Max How…

Java設計模式之創建型—建造者模式

Java中最常用的設計模式-CSDN博客 “把對象的構造步驟拆成鏈式方法&#xff0c;調用者按需填參&#xff0c;最后一次性 build&#xff0c;避免構造函數爆炸。” 經典場景 參數多&#xff08;>4 個&#xff09;且大部分可選 需要不可變對象&#xff08;final 字段&#xf…

網頁計時器,支持多計時器管理、數據分享、用戶數據同步、全屏展示等功能,可進行倒計時、正計時和顯示世界時鐘。

一個具有現代化 UI 和交互的計時器網頁應用&#xff0c;支持多計時器管理、數據分享、用戶數據同步、全屏展示等功能&#xff0c;可進行倒計時、正計時和顯示世界時鐘。它采用玻璃態設計和流暢動畫效果&#xff0c;提供極佳的視覺體驗。 特點&#xff1a; 支持多個計時器的創建…

紋理融合——用 TypeScript + Babylon.js 打造“可混合紋理序列”

我不想搞個一新的Shader&#xff0c;我就想用已有的材質&#xff08;比如StandardMaterial和PBRMetallicRoughnessMaterial&#xff09;實現紋理融合漸變等效果&#xff0c;于是我搞了一個TextureBlender。一、為什么重復造輪子&#xff1f;GPU 插值受限material.diffuseTextur…

【完整源碼+數據集+部署教程】公交車部件實例分割系統源碼和數據集:改進yolo11-fasternet

背景意義 隨著城市化進程的加快&#xff0c;公共交通系統的需求日益增加&#xff0c;公交車作為城市交通的重要組成部分&#xff0c;其運行效率和安全性直接影響到城市的交通狀況和居民的出行體驗。因此&#xff0c;公交車的維護和管理顯得尤為重要。在這一背景下&#xff0c;公…

【C++題解】關聯容器

關于set&#xff0c;map以及變種 |關聯容器| set&multiset | map&multimap |無序關聯容器| Unordered set&multiset | Unordered map&multimap | 建議先了解之后再配合練習 這次練習CCF真題比較多&#xff0c;也比較基礎&#xff0c;預計耗時不用這么久。 今天…

【智譜清言-GLM-4.5】StackCube-v1 任務訓練結果不穩定性的分析

1. Prompt 我是機器人RL方向的博士生正在學習ManiSkill&#xff0c;在學習時我嘗試使用相同命令訓練同一個任務&#xff0c;但是我發現最終的 success_once 指標并不是相同的&#xff0c;我感到十分焦慮&#xff0c; 我使用的命令如下&#xff1a; python sac.py --env_id&qu…

MySQL 8.0 主從復制原理分析與實戰

MySQL 8.0 主從復制原理分析與實戰半同步復制設計理念&#xff1a;復制狀態機——幾乎所有的分布式存儲都是這么復制數據的基于全局事務標識符&#xff08;GTID&#xff09;復制GTID工作原理多主模式多主模式部署示例課程目標&#xff1a; MySQL 復制&#xff08;Replication&a…

[UT]記錄case中seq.start(sequencer)的位置變化帶來的執行行為的變化

現象&#xff1a; 代碼選擇打開57行&#xff0c;注釋掉60行執行&#xff0c;結果58行不會打印。 代碼選擇打開60行&#xff0c;注釋57行執行&#xff0c;結果58行正常打印。 sequence的執行需要時間&#xff01;&#xff01;&#xff01; SV中代碼57行切換到60行的區別&#xf…

利用keytool實現https協議(生成自簽名證書)

利用keytool實現https協議&#xff08;生成自簽名證書&#xff09;什么是https協議&#xff1f;https&#xff08;安全超文本傳輸協議&#xff09;是 HTTP 的安全版本&#xff0c;通過 SSL/TLS 加密技術&#xff0c;在客戶端&#xff08;如瀏覽器&#xff09;和服務器之間建立加…

拆解 AI 大模型 “思考” 邏輯:從參數訓練到語義理解的核心鏈路

一、引言&#xff1a;揭開 AI 大模型 “思考” 的神秘面紗?日常生活中的 AI 大模型 “思考” 場景呈現&#xff08;如 ChatGPT 對話、AI 寫作輔助、智能客服應答&#xff09;?提出核心問題&#xff1a;看似具備 “思考” 能力的 AI 大模型&#xff0c;其背后的運作邏輯究竟是…

element plus 使用細節 (二)

接上一篇文章&#xff1a; element plus 使用細節 最近菜鳥忙于系統開發&#xff0c;都沒時間總結項目中使用的問題&#xff0c;幸好還是在空閑之余總結了一點&#xff08;后續也會來補充&#xff09;&#xff0c;希望能給大家帶來幫助&#xff01; 文章目錄table fixed 的 v…

【機器學習學習筆記】numpy基礎2

零基礎小白的 NumPy 入門指南如果你想用電競&#xff08;打游戲&#xff09;的思路理解編程&#xff1a;Python 是基礎操作鍵位&#xff0c;而 NumPy 就是 “英雄專屬技能包”—— 專門幫你搞定 “數值計算” 這類復雜任務&#xff0c;比如算游戲里的傷害公式、地圖坐標&#x…

從自動化到智能化:家具廠智能化產線需求與解決方案解析

伴隨著工業4.0浪潮和智能制造技術的成熟&#xff0c;家具行業正逐步從傳統的自動化生產邁向智能化生產。智能化產線的構建不僅可以提升生產效率&#xff0c;還能滿足個性化定制和柔性制造的需求。本文以某家具廠為例&#xff0c;詳細解析智能化產線的核心需求&#xff0c;并提出…

macOS下基于Qt/C++的OpenGL開發環境的搭建

系統配置 MacBook Pro 2015 Intel macOS 12Xcode 14 Qt開發環境搭建 Qt Creator的下載與安裝 在Qt官網的下載頁面上下載&#xff0c;即Download Qt Online Installer for macOS。下載完成就得到一個文件名類似于qt-online-installer-macOS-x64-x.y.z.dmg的安裝包。 下一步 …

當液態玻璃計劃遭遇反叛者:一場 iOS 26 界面的暗戰

引子 在硅谷的地下代碼俱樂部里&#xff0c;流傳著一個關于 “液態玻璃” 的傳說 —— 那是 Apple 秘密研發的界面改造計劃&#xff0c;如同電影《變臉》中那張能改變命運的面具&#xff0c;一旦啟用&#xff0c;所有 App 都將被迫換上流光溢彩的新面孔。 而今天&#xff0c;我…

探究Linux系統的SSL/TLS證書機制

一、SSL/TLS證書的基本概念 1.1 SSL/TLS協議簡介 SSL/TLS是一種加密協議&#xff0c;旨在為網絡通信提供機密性、完整性和身份驗證。它廣泛應用于HTTPS網站、電子郵件服務、VPN以及其他需要安全通信的場景。SSL&#xff08;安全套接字層&#xff09;是TLS&#xff08;傳輸層安全…