QT學習筆記(2) 訊號與槽

2021-07-10 17:01:36 字數 4503 閱讀 3291

1 moc(元物件)系統簡介

在 qt 助手的索引裡面輸入「the meta-object system」,就可以看到元物件系統的英文文件。現在將其主要的內容描述如下:

qt 元物件系統實現了物件之間通訊機制——訊號和槽,並提供了執行時型別資訊和動態屬性系統。元物件系統是 qt 類庫獨有的功能,是 qt 對標準 c++ 的擴充套件,並且元物件系統本身也是由純 c++ 語言寫成的,所以學好 c++ 是必須的。使用元物件系統的前提是需要三件事情:

(1)直接或間接地以 qobject 為基類,這樣才能利用元物件系統的功能,qt 的窗體和控制項最頂層的基類都是 qobject。

(2)將 q_object 放在類宣告的私有段落,以啟用元物件特性,如動態屬性、訊號和槽等。如q_object 都是在類宣告裡的第一行,沒有加 private 字樣,因為類宣告預設就是私有的。

(3)元物件編譯器(meta-object compiler,moc)為每個 qobject 的子類提供必要的**以實現元物件特性。

注意:

只有繼承了 qobject 類的類,才具有訊號槽的能力。所以,為了使用訊號槽,必須繼承 qobject。凡是 qobject 類(不管是直接子類還是間接子類),都應該在第一行**寫上 q_object。不管是不是使用訊號槽,都應該新增這個巨集。這個巨集的展開將為我們的類提供訊號槽機制、國際化機制以及 qt 提供的不基於 c++ rtti 的反射能力。

除了提供訊號和槽機制用於物件之間的通訊(這是主要任務),元物件系統還提供了更多的特性:

(1)qobject::metaobject() 函式返回當前類物件關聯的元物件(meta-object)。

(2)qmetaobject::classname() 函式返回當前物件的類名稱字串,而不需要 c++ 編譯器原生的執行時型別資訊(run-time type information,rtti)支援。

(3)qobject::inherits() 函式判斷當前物件是否從某個基類派生,判斷某個基類是否位於從 qobject 到物件當前類的繼承樹上。

(4)qobject::tr() 和 qobject::trutf8() 函式負責翻譯國際化字串,因為 qt5 規定原始檔字元編碼是 utf-8,所以這兩個函式現在功能是一樣的。

(5)qobject::setproperty() 和 qobject::property() 函式用於動態設定和獲取屬性,都通過屬性名稱字串來 操作。

(6)qmetaobject::newinstance() 構建乙個當前類的新例項物件。

2 訊號與槽

(1)乙個訊號可以連線多個槽;

(2)多個訊號可以連線在同乙個槽上;

(3)乙個訊號可以與另外乙個訊號相連線;

(4)連線可以被移除;

3 訊號與槽使用格式

(1)qt4和qt5通用的格式如下:

qmetaobject::connection qobject::​connect(const qobject * sender, const char * signal, const qobject * receiver, const char * method, qt::connectiontype type = qt::autoconnection)

connect(sender, signal(signal), receiver, slot(slot))

頭兩個引數是源頭物件和訊號,後兩個引數接收物件和槽函式,sender和receiver是指向qobject的指標,signal和slot是不帶引數的函式名。這種句式可讀性很好,訊號和槽的標識也很清晰。connect 函式返回型別是 qmetaobject::connection ,可以用於執行時判斷關聯是否正確,或者用於解除關聯。

注意到 connect 函式引數裡的 signal 和 method(槽函式)都是 char * 字串型別,所以舊式語法的 connect 函式是根據訊號和槽函式的字串名稱來關聯的,不具備編譯時型別檢查,大家都是字串,引數型別在編譯時都不知道。關聯出錯只有在執行時才會體現。引數使用時要注意:

(1)將函式名轉為char *字串可使用signal和slot兩個巨集,注意函式包括函式名以及形參型別,但不包括形參。如:connect(ui->pushbutton, signal(clicked()), this, slot(foodiscoming(int, double)));

(2)receiver是指向qobject的指標,是包含槽函式的類,當connect在類內部(成員函式內)使用時,receiver要指向這個類本身,可用this指標;當connect在類外部中使用時,receiver要指向類物件,用&符號。

最後的關聯型別引數一般我們都使用預設值 qt::autoconnection,這在多執行緒程式設計的時候才會有講究。對於單執行緒的,關聯一般用直連型別(qt::directconnection),訊號一觸發, 對應槽函式立即就被呼叫執行;對於多執行緒程式,跨執行緒的關聯一般用入隊關聯(qt::queuedconnection),訊號觸發後,跨執行緒的槽函式被加入事件 處理佇列裡面執行,避免干擾接收執行緒裡的執行流程。qt::autoconnection 會自動根據源頭物件和接收物件所屬的執行緒來處理,預設都用這種型別的關聯,對於多執行緒程式這種關聯也是安全的。

(2)qt5 為了能夠盡早檢查關聯型別和引數的匹配情況,引入了新的函式指標關聯語法,這樣在程式編譯時就能發現關聯正確與否。新式語法格式如下:

qmetaobject::connection qobject::​connect(const qobject * sender, pointertomemberfunction signal, const qobject * receiver, pointertomemberfunction method, qt::connectiontype type = qt::autoconnection)
與舊語法句式區別就在於 signal 和 method (槽函式),新句式用的是 pointertomemberfunction (相當於函式指標),這個型別名稱是不存在的,只是在文件裡面顯示,方便程式設計師看的,實際使用的是模板函式。具體模板函式定義比較複雜,比較關鍵的就是兩個函式引數型別需要一致,或者訊號聲 明時的引數更多更廣。因為訊號本身是不幹活的,它多點引數無所謂,但必須保證槽函式執行時需要的引數是一定有的。

connect(serial_ptr, signal(readyread()), this, slot(serial_getdata()));

connect(serial_ptr, &qserialport::readyread, this, &serialwindow::serial_getdata);

注意使用新格式時,訊號函式與槽函式只有函式名,而且必須加上類作用域,並在前加上&符號。

最後提醒一下,不管使用舊句式,還是新句式,關聯的源頭和接收端一定是實際存在的物件,ui->pushbutton 這個按鈕物件成功建立之後,上面的關聯才能正常執行。雖然新句式可以用 &qpushbutton::clicked 這個函式指標形式,但注意第乙個和第三個引數是實際的物件,這是把源頭物件關聯到接收端物件,而不是把類關聯到類!如果沒有定義物件實體,關聯函式就沒意義。

4 自定義訊號與槽

4.1 自定義訊號與槽的一般步驟

(1)傳送者和接收者都需要是 qobject 的子類(槽函式是全域性函式、 lambda 表示式等無需接收者的時候除外);

(2)使用 signals 標記訊號函式,訊號是乙個函式宣告(可以有引數),返回 void,不需要實現函式**

(3)槽函式是普通的成員函式,作為成員函式,會受到 public、 private、 protected 的影響;

(4)使用 emit 在恰當的位置傳送訊號;

(5)使用 qobject::connect()函式連線訊號和槽。

4.2 訊號接力

connect(sender, signal(signal1), receiver, signal(signal2))
注意:這種方法signal2下的形參一般是void型,無法發出帶引數的訊號(可以在槽函式中使用emit來實現發出帶引數的訊號)。

signals:

void sendvoid();

//clicked()訊號發出後會立即發出sendvoid()訊號

connect(ui->pushbutton, signal(clicked()), this, signal(sendvoid()));

public slot:

void recvvoid();

connet(&w, signal(sendvoid()), &s, slot(recvvoid()));

Qt學習筆記 訊號與槽

訊號和槽用於兩個物件之間的通訊,是qt的核心特徵和突出特徵。當乙個特殊的事件發生時,相關物件便會發出乙個訊號,比如單擊滑鼠 按鍵等。槽就是乙個函式,用來響應訊號,可以自定義或者使用已存在的函式。訊號和槽的對應關係 乙個訊號何以關聯到多個槽,乙個槽也可以關聯多個訊號,甚至乙個訊號也可以關聯到另乙個訊號...

QT學習 訊號與槽

最近在學習qt訊號與槽。先看看我自己寫的乙個demo.這個demo沒有窗體。在qt creator中新建乙個 空的qt專案 pro檔案如下 templateheaders mysignal.h myslot.hsources mysignal.cpp myslot.cpp main.cpp包含三個c...

QT學習筆記 5 訊號槽

模態對話方塊 相當於在已經開啟乙個對話方塊1的前提下,開啟對話方塊2,這時,是無法操作對話方塊1的。非模態對話方塊則相反。若要處理訊號的時候,記得在.pro檔案上面加上 config c 11模態對話方塊與非模態對話方塊的區別主要是在於 模態 qdialog dlg dlg.exec exec 執行...