Qt 原始碼剖析 訊號槽自動連線機制

2021-09-24 08:17:29 字數 2916 閱讀 7861

我們在使用 qt 建立乙個視窗 mywidget 時, qt creator 會幫我們建立出 "mywidget.h", "mywidget.cpp", "mywidget.ui" 這三個檔案. 我們使用 qt designer 開啟 mywidget.ui 檔案, 拖乙個 qpushbutton 上去, qt designer 預設給這個按鈕設定乙個物件名 "pushbutton". 在該按鈕上右鍵選擇轉到槽, 選擇clicked()訊號, qt creator 就會在 mywidget 類中生成乙個槽函式void on_pushbutton_clicked(). 我們只需要在這個槽函式中新增自己的邏輯就行了.

有沒有感覺到和平時自己寫訊號槽的時候不一樣? 沒有 connect? 但是程式跑起來, 按下按鈕就自動執行該槽函式了呀. 從結果看, 肯定是 connect 過了. 所以我們不難想到, 一定是訊號槽被自動 connect 了.

如果讓我們自己實現的話, 將乙個物件的槽函式與其ui檔案中定義的某物件的訊號連線起來, 需要以下幾步:

規定乙個 可自動連線的槽函式 的命名格式, 其中需要包含這些資訊: 哪個物件傳送了訊號, 傳送了什麼訊號. 這樣我們就知道需要自動連線哪些槽函式了.

遍歷傳入的這個物件的所有方法. 找到符合命名規範的槽函式.

遍歷這個物件及其子物件, 找到訊號的傳送物件, 再找到該物件的相應訊號. 完成連線.

我們知道 "mywidget.ui" 檔案會被處理, 並生成 "ui_mywidget.h" 檔案. 這個檔案會被包含在 mywidget 類的實現中. 那我們就先來看看這個 "ui_mywidget.h" 檔案吧.

ui_mywidget.h 中有乙個 ui_mywidget 類. 我們在類成員變數中發現了qpushbutton *pushbutton;, 這個就是我們之前拖上去的按鈕. 除此之外, 還有兩個成員函式void setupui(qwidget *mywidget)void retranslateui(qwidget *mywidget).

我們知道 retranslateui 函式是在當程式語言改變時, 用來重新整理ui中顯示語言的. 是國際化相關的內容, 在這裡我們先忽略. 我們先看看 setupui 函式中做了些什麼.

void

setupui

(qwidget *mywidget)

// setupui

複製**

在最後呼叫了qmetaobject::connectslotsbyname()函式, 從函式名我們就知道其功能是 "通過名字連線槽函式". 這麼看來, 自動連線訊號槽就是它做的了. qmetaobject 在 "qobjectdefs.h" 中定義, 在 "qobject.cpp" 中實現.

qobjectdefs.h

struct

q_core_export

qmetaobject

複製**

我們先看一下該函式的文件說明:

我們再看它是如何實現的:

void qmetaobject::connectslotsbyname(qobject *o)

複製**

qobjectlist list中儲存了 o 及其所有子物件. 接下來看 "[1]"**.

// for each method/slot of o ...

for (int i = 0; i < mo->methodcount(); ++i) else

if (!(mo->method(i).attributes() & qmetamethod::cloned))

}複製**

開始遍歷該物件的所有成員方法, 找到以on_開頭的方法. 然後遍歷儲存所有物件的列表 list. (遍歷過程後面再說). 如果找到匹配的了, 就跳過該方法的過載函式. 如果未找到, 確定該函式符合on__()格式, 然後列印 warning 資訊.

接下來就看 "[2]" **. 看看在遍歷物件列表時都做了些什麼.

for(int j = 0; j < list.count(); ++j) 

} if (compatiblesignals.size() > 1)

qwarning() << "qmetaobject::connectslotsbyname: connecting slot"

<< slot

<< "with the first of the following compatible signals:"

<< compatiblesignals;

} if (sigindex < 0)

continue;

// we connect it...

if (connection(qmetaobjectprivate::connect(co, sigindex, smeta, o, i)))

}複製**

遍歷物件列表, 找到符合本槽函式 object name 的物件. 然後查詢該物件的是否有完全符合 singnalname + 引數列表 的訊號.

如果沒有找到, 則繼續查詢至少滿足該槽引數列表的訊號. (因為訊號的引數個數可以大於槽引數個數). 如果多個訊號都符合要求, 就按照訊號在原始檔中的宣告順序, 選擇第乙個, 並列印乙個 warning 資訊.

之後, 將該訊號與槽進行連線, 並退出該迴圈. 所以說, 如果存在相同 object name 的物件, 也只連線第乙個. 其他的都會被忽略. (qt designer 會確保 object name 的唯一性, 但其他**新增的 object name 就不受控制了).

Qt訊號槽自動關聯

想要槽函式自動關聯訊號,槽函式名稱必須遵循以下規則 void on 注意 這裡是物件名稱,也就是setobjectname設定的名稱,例如 qpushbutton pbutton new qpushbutton this pbutton setobjectname startbutton void ...

Qt訊號與槽連線

connect pointer1,pointer2,pointer3,pointer4 pointer1 指向傳送訊號的物件的指標 pointer2 傳送訊號的物件所對應的類的成員函式的指標 pointer3 接收訊號的物件的指標 pointer4 接收訊號的物件所對應物件的槽函式指標 總結下來就是...

Qt 訊號與槽自動關聯

原型 static void qmetaobject connectslotsbyname qobject object 遞迴搜尋給定物件的所有子物件,並將匹配訊號從它們連線到遵循以下形式的物件插槽 void on 假設我們的物件具有qpushbutton型別的子物件,其物件名稱為button1。捕...