Qt Creator 源碼學(xué)習(xí)筆記 05,菜單欄是怎么實現(xiàn)插件化的?

閱讀本文大概需要 6 分鐘
對于一個多插件的?IDE
?軟件來說,支持界面擴(kuò)展是必不可少的,今天我們來看看在?Qt Creator
?當(dāng)中是如何實現(xiàn)界面擴(kuò)展的
概述
界面擴(kuò)展無非就是在其它插件中訪問修改主界面當(dāng)中的一些菜單、參數(shù),或者添加、刪除某些菜單,目前很多大型軟件都是支持插件化開發(fā)的
前幾篇我們一起看了Qt Creator
的主界面其實很簡單,主界面包括一個菜單欄,模式工具欄,內(nèi)容區(qū)域以及狀態(tài)欄,如下圖所示:

我們看到的其它豐富功能均是通過插件化實現(xiàn)的,今天我們詳細(xì)學(xué)習(xí)下看看?QTC
?當(dāng)中菜單欄是怎么實現(xiàn)擴(kuò)展的
實現(xiàn)原理
“在學(xué)習(xí)代碼之前我們可以想一想,如果讓我們自己來實現(xiàn)應(yīng)該如何實現(xiàn),比如擴(kuò)展一個
Menu
菜單?
既然其他插件要擴(kuò)展,那么肯定需要訪問核心插件創(chuàng)建的?menu
?對象,那么就必須要有訪問權(quán)限,那么核心插件定義的?menu
?對象應(yīng)該有哪些權(quán)限呢?

仔細(xì)回憶下我們剛開始學(xué)習(xí)?C/C++
?的時候老師就給我們說過,定義一個變量/對象要注意哪些關(guān)鍵點?
變量/對象的名
變量/對象的值
變量/對象的作用域
變量/對象的生命周期
所以我們要實現(xiàn)一個菜單也是需要考慮這幾個方面,最關(guān)鍵的是這個對象的生命周期,外部要能訪問該對象可以有好幾種方式:暴露指針給外使用、提供注冊接口、定義單例……,其實把?menu
定義成一個單例是最便捷最靈活的一種方式了,類似下面這種
PS: 定義接口或者暴露指針也可以,只不過每次訪問還要先訪問核心插件對象,處理起來比較繁瑣罷了
源碼實現(xiàn)
好了,下面我們看下源碼是怎么實現(xiàn)的
菜單管理代碼主要在這個位置 : /Src/plugins/.coreplugin/actionmanager

文件雖然看著很多,不用擔(dān)心,我們主要關(guān)心的類有這么幾個:
ActionContainer
ActionContainerPrivate
MenuActionContainer
MenuBarActionContainer
ActionManager
這幾個類之間繼承關(guān)系如下所示:

黃色表示的類對內(nèi)使用,外部看不到具體的實現(xiàn),每個菜單都可以是一個?MenuActionContainer
?對象,MenuBarActionContainer
全局只有一份,相當(dāng)于是一個容器來容納所有的菜單
那么我們?nèi)绾蝿?chuàng)建一個菜單呢?其中有專門管理創(chuàng)建、注冊的類來實現(xiàn),這是一個單例類
在這個單例類當(dāng)中,主要有兩個重要的數(shù)據(jù)結(jié)構(gòu)用來存儲創(chuàng)建的菜單對象,詳細(xì)實現(xiàn)都在它的?D
指針里面
使用哈希Map 來存儲每個對象,當(dāng)創(chuàng)建的菜單對象比較多時查找效率非常高,同時注意鍵值key
?是一個自定義的字符串ID
,由特殊規(guī)則構(gòu)成的全局唯一的值
其中有一個比較重要的數(shù)據(jù)結(jié)構(gòu)?Context
這個類其實就是一個字符串?ID
?的數(shù)組封裝,各個菜單的標(biāo)識、狀態(tài)控制都用到了它,這個結(jié)構(gòu)貫穿整個?Qt Creator
插件系統(tǒng),使用起來還是非常方便的
有了上面的結(jié)構(gòu),那么如何創(chuàng)建菜單以及子菜單呢,下面我們詳細(xì)看下
創(chuàng)建 MenuBar
這里沒啥好說的,和我們平時在QMainWindow
當(dāng)中創(chuàng)建方法一樣,只不過這里創(chuàng)建細(xì)節(jié)統(tǒng)一封裝管理起來了
創(chuàng)建菜單
下面我們以「文件」菜單為例看下創(chuàng)建過程

這兩行代碼就完成了「文件」菜單的創(chuàng)建,代碼很簡潔也非常容易理解,這里我們需要注意下幾個常量定義技巧
所有的菜單都是通過字符串常量來區(qū)分的,這個常量相當(dāng)于現(xiàn)實世界中我們每個人的身份證都是唯一的,而且都是有規(guī)律的
PS:看到這里再問大家一個問題,定義常量時,宏定義寫法和上面的寫法哪個好?為什么?歡迎討論
到了這里,僅僅是創(chuàng)建了菜單,點擊菜單后內(nèi)容還是空的,我們接著繼續(xù)看
每個action
創(chuàng)建后通過?addAction
?添加到對應(yīng)的菜單上即可,如果某個?action
?還有子菜單,那么就需要先創(chuàng)建一個菜單,然后直接添加菜單即可,比如「最近訪問的文件」

任意一個action
可以擁有多個子菜單,只需要在創(chuàng)建的時候根據(jù)遞歸關(guān)系選擇創(chuàng)建action
還是ActionContainer
測試
為了驗證上述流程分析是否正確,我們可以編譯一個測試插件,然后在該插件里面新創(chuàng)建一個菜單,分為下面幾個流程:
創(chuàng)建測試插件
PluginDemo
子工程;在插件初始化函數(shù)當(dāng)中創(chuàng)建菜單;
編譯該插件,然后把該插件(動態(tài)庫)拷貝到?
QTC
?對應(yīng)插件目錄下運行軟件
創(chuàng)建插件編譯后生成的目錄結(jié)構(gòu)如下所示:

可以看到我們測試插件路徑和程序?exe
是獨立的
運行軟件顯示效果如下所示

可以看到整個代碼不超過 10行就把創(chuàng)建的菜單添加到了主界面當(dāng)中,使用起來目前看來還是很方便的,而且方便擴(kuò)展,由于使用插件化和其它模塊進(jìn)行了解耦
相信大家也都看到了,QTC
?插件系統(tǒng)當(dāng)中比較重要的ID
編號問題,這些編號都有固定的格式,而且每個ID
無論從命名還是具體內(nèi)容表達(dá)的意思都是顯而易見的
M
開頭表示菜單名字,比如文件、編輯、視圖、構(gòu)建……G
開頭表示分組信息,比如文件菜單當(dāng)中包含了:新建文件、打開文件、打開工程、保存文件……
總結(jié)
Qt Creator
界面插件化內(nèi)容還很多,本次只是簡簡單單地學(xué)習(xí)了菜單管理邏輯以及如何使用,如果想了解更多細(xì)節(jié)閱讀對應(yīng)源碼即可
一款優(yōu)秀的開源軟件有很多內(nèi)容值得我們反復(fù)去學(xué)習(xí)、理解、使用的,未來很長,我們繼續(xù)……
PS:文中涉及到相關(guān)流程圖以及對應(yīng)源碼,如果感興趣可以后臺私信發(fā)給你
如果覺得對你有幫助,歡迎留言互相交流學(xué)習(xí)
推薦閱讀
Qt Creator 源碼學(xué)習(xí)筆記01,初識QTC
Qt Creator 源碼學(xué)習(xí)筆記02,認(rèn)識框架結(jié)構(gòu)結(jié)構(gòu)
Qt Creator 源碼學(xué)習(xí)筆記03,大型項目如何管理工程
Qt Creator 源碼學(xué)習(xí)筆記04,多插件實現(xiàn)原理分析