Qt的Signals 和 Slots詳解

Qt::AutoConnection的signal-slot連接是在運(yùn)行時確定連接類型,多線程安全的。

Qt中的關(guān)鍵字:signals 其實(shí)就是public;而slots則什么都沒有。

Signals 和 Slots 用于對象間的通信(communication between objects)。這種機(jī)制是Qt區(qū)別于其他框架的主要特點(diǎn)。這種機(jī)制是靠Qt的meta-object system實(shí)現(xiàn)的。

介紹

很多框架使用callback技術(shù)(MFC,CVI等)。一個 callback 其實(shí)就是一個函數(shù)指針,但是Qt認(rèn)為callback并不直觀,而且在callback參數(shù)上容易出問題。

信號與槽

在Qt中使用另一種方案:信號與槽。信號在特定事件發(fā)生時被發(fā)射。Qt widgets有很多預(yù)定義的信號。我們可以子類化widgets來添加自己的信號。槽函數(shù)在所連接信號發(fā)射后被調(diào)用,作為事件的響應(yīng)。? ? Qt widgets有很多預(yù)定義的槽。實(shí)際中我們經(jīng)常子類化widget來添加自己的槽函數(shù),來響應(yīng)感興趣的信號。


信號與槽:對象間通信

信號與槽機(jī)制是類型安全的:信號的簽名必須和槽一致(實(shí)際槽的簽名可以比信號更短,忽略部分參數(shù))。由于簽名兼容,編譯器可以幫助我們檢查類型是否匹配。基于字符串的 SIGNAL 和 SLOT 語法可以在運(yùn)行階段檢查類型匹配。

所有繼承自QObject的類都可以包含信號和槽。槽函數(shù)既可以用來接收信號,也可以當(dāng)做普通函數(shù)使用。

信號和槽可以是一對多、多對一。也可以把一個信號連接到另一個信號(這樣第一個信號發(fā)射后會接著發(fā)射第二個信號)。callback技術(shù)(即函數(shù)指針)只能是一對一。

信號/槽非常類似于C#中事件(event)的發(fā)布和訂閱。

信號

信號是 public 類型的,可以從任何地方發(fā)射。但是推薦在定義信號的類內(nèi)部發(fā)射(signals are public access functions and can be emitted from any where, but we recommend to only emit them from the class that defines the signals and its subclasses)。

Qt中的關(guān)鍵字:signals 其實(shí)就是public;而slots則什么都沒有。

(信號非常類似C#中的事件event,可以被訂閱)

當(dāng)信號發(fā)射時,連接的槽函數(shù)通常立即執(zhí)行(direct connection),就像普通的函數(shù)調(diào)用。此時信號和槽機(jī)制與GUI的事件循環(huán)是獨(dú)立的。emit 之后的代碼在所有槽函數(shù)返回后才會被執(zhí)行(正常,此時的信號-槽,就是函數(shù)指針-函數(shù))。這和 queued connections 不同,后者是立即執(zhí)行 emit 之后的代碼,而槽函數(shù)在晚些時候執(zhí)行。

如果多個槽連接到一個信號,當(dāng)信號發(fā)射時,槽函數(shù)的執(zhí)行順序就是連接的順序。

信號由moc自動生成,不可以在.cpp文件中實(shí)現(xiàn),而且也不能有返回類型(即只能使用void)。

槽函數(shù)就是普通的C++函數(shù)。唯一特別的地方是:可以連接到信號。

槽函數(shù)可以通過 信號-槽 的連接而被任何組件調(diào)用,這與槽的訪問權(quán)限無關(guān)。這意味著private 的槽也可以被信號調(diào)用。(However, as slots, they can be invoked by any component, regardless of its access level, via a signal-slot connection.This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class)

槽函數(shù)是普通的成員函數(shù)。也可以定義成virtual類型,非常有用。

信號-槽機(jī)制比callback機(jī)制的速度略慢,這是增加了靈活性的代價,但是差異并不大。通常,發(fā)射一個信號來調(diào)用槽函數(shù),通常比直接調(diào)用函數(shù)慢10倍(10 times slower tha calling the receivers directly),時間主要用來確定接收對象,來安全的遍歷連接(例如檢查后續(xù)的信號接收者沒有被銷毀),來封送參數(shù)。

信號-槽機(jī)制消耗的時間比 new 和delete所消耗的時間更短。考慮到它的靈活性,這些實(shí)現(xiàn)消耗是值得的。

例子

#include <QObject>

? class Counter : public QObject

? {

? ? ? Q_OBJECT

? public:

? ? ? Counter() { m_value = 0; }

? ? ? int value() const { return m_value; }

? public slots:

? ? ? void setValue(int value);

? signals:

? ? ? void valueChanged(int newValue);

? private:

? ? ? int m_value;

? };

包含信號和槽的類必須滿足兩個條件:

1. 在聲明的最頂部使用 Q_OBJECT;

2.直接或間接繼承自QObject。

void Counter::setValue(int value)

? {

? ? ? if (value != m_value) {

? ? ? ? ? m_value = value;

? ? ? ? ? emit valueChanged(value);

? ? ? }

? }

Counter a, b;? ? ? QObject::connect(&a, &Counter::valueChanged,? ? ? ? ? ? ? ? ? ? ? &b, &Counter::setValue);?

a.setValue(12);? ? // a.value() == 12, b.value() == 12

? ? b.setValue(48);? ? // a.value() == 12, b.value() == 48

信號和槽的連接類型

Qt::AutoConnection

默認(rèn)連接方式。當(dāng)receiver在于發(fā)射信號的線程里時(線程親和性),使用的是Qt::DirectConnection. 多線程時則使用Qt::QueuedConnnection。連接類型在信號發(fā)射時確定(運(yùn)行時,而非編譯時)。

Qt::DirectConnection

信號發(fā)射時立即調(diào)用槽函數(shù)。槽在信號發(fā)射的線程里執(zhí)行。

Qt::QueuedConnnection

當(dāng)控制權(quán)回到receiver所在線程時才執(zhí)行槽函數(shù)。槽函數(shù)在receiver的線程里執(zhí)行。

Qt::BlockingQueuedConnection

和QueuedConnection類似。但是發(fā)射信號的線程會阻塞,直到槽函數(shù)返回。當(dāng)receiver和sender在同一個線程里時,不可以使用該方式,否則會發(fā)生死鎖。

Qt::UniqueConnection

該類型可以和上面的類型配合,用或“|”處理即可。當(dāng)連接已經(jīng)存在時,再次連接會失敗。其實(shí)就是為了保證連接的唯一性。

注意:當(dāng)使用QueuedConnection時,參數(shù)類型必須是 Qt 的 meta-object system 知道的類型,因為Qt要拷貝參數(shù)??梢詂onnect()前調(diào)用qRegisterMetaType()來注冊數(shù)據(jù)類型。

關(guān)于信號和槽在多線程中的使用,參考“QObjects和多線程”。



參考Qt官方文檔:"Signals & Slots".

QT多線程深入分析






最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 為什么在頭文件中有的是使用前置聲明,而有的是包含頭文件? 如下代碼: 前置聲明(forward declarati...
    Joe_HUST閱讀 1,447評論 0 6
  • 信號和槽(Signals and Slots) Qt庫第一個認(rèn)識到在幾乎所有情況下,程序員不需要或甚至不想知道所有...
    珞珈村下山閱讀 10,146評論 0 23
  • 1、概述 信號槽是 Qt 框架引以為豪的機(jī)制之一。所謂信號槽,實(shí)際就是觀察者模式。當(dāng)某個事件發(fā)生之后,比如,按鈕檢...
    你的社交帳號昵閱讀 45,839評論 0 9
  • 韓元旭、余橙、沈開洋 Qt介紹 Qt是一個跨平臺的C++圖形用戶界面應(yīng)用程序框架。它早在1991年奇趣科技公司兩位...
    開洋_shen閱讀 16,424評論 4 24
  • 轉(zhuǎn)自:作者簡介作者:唐新華 (xhsmart@263.net)軟件工程師 ?? 信號和槽作為QT的核心機(jī)制在QT編...
    njukay閱讀 1,415評論 0 49

友情鏈接更多精彩內(nèi)容