深入理解Qt訊號和槽機制、訊號和槽中的Lambda表示式
對於事件處理,MFC中使用的是訊息對映機制,Qt使用的是訊號和槽機制,在我看來,Qt的訊號和槽比MFC功能更強大,也更靈活。1、訊號和槽的簡單介紹: 一般格式:
connect(Sender,SIGNAL(signal),Receiver,SLOT(slot));
connect(訊號傳送者,訊號,訊號接受者,槽函式);
- 1
- 2
做個很簡單的比喻:運動比賽,裁判員鳴槍,運動員起跑,訊號傳送者是裁判,訊號是槍聲;訊號接受者是運動員,槽函式(對訊號做出的相應)是起跑。
所有的QObject都可以使用訊號和槽機制,而Qt中的大部分類都是繼承於QObject,SIGNAL()和()SLOT()是Qt定義的兩個巨集,他們返回其引數的C語言風格的字串(const *char,訊號加字首2,槽加字首1),因此下面的兩個語句是相同的: connect(Object2,SIGNAL(clicked()),Object3,SLOT(functionA())); connect(Object2,”2clicked()”,Object3,”1functionA()”); 例如:
QTimer *mytimer = new QTimer(this);
mytimer->start(1000);
connect(mytimer,"2timeout()",this,"1my_slot()");
- 1
- 2
- 3
需要注意的是:不論是訊號還是槽函式,在SIGNAL()和SLOT()中使用時,引數只能包含變數型別,不能包含變數名
2、訊號和槽的變化:
//一個訊號可以與另一個訊號相連 connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal2)); //同一個訊號可以與多個槽相連,此時呼叫槽的順序是隨機的 connect(Object1,SIGNAL(signal1),Object2,SLOT(slot1)); connect(Object1,SIGNAL(signal1),Object3,SLOT(slot2)); //同一個槽也可以響應多個訊號 connect(Object1,SIGNAL(signal1),Object3,SLOT(slot1)); connect(Object2,SIGNAL(signal2),Object3,SLOT(slot1)); //連線也可以被移除,當然,這種情況很少見,因為物件被刪除時,Qt會自動移除該物件相關的所有連線 disconnect(Sender,SIGNAL(signal),Receiver,SLOT(slot)); //要把訊號和槽(或訊號)成功連線,被連線的兩者,其引數必須有相同的順序和型別,這裡有個例外是,如果訊號的引數比它連線的槽的引數多,多餘的引數會被簡單的忽略掉 connect(Object1,SIGNAL(signal(int,const QString&)),Object2,SIGNAL(signal(int,const QString&));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3、Qt5中訊號和槽的擴充套件3.1、
C++11中增加了蘭布達表示式(Lambda),在Qt5的訊號和槽中,也可以使用蘭布達表示式:
由於用了C++11的特性,需要在.pro
檔案中新增:CONFIG += C++11
QTimer *mytimer = new QTimer(this); mytimer->start(1000); //Lambda表示式對應的訊號必須是函式指標形式 connect (mytimer ,&QTimer::timeout, [=]() { //dosomething,訊號發出之後,需要做的事情 } );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
方括號內代表可用的實體(變數、控制元件等),多個可用逗號隔開,方括號內還可以放一些好用的運算子:
[=] () {}
Lambda函式體內可以使用Lambda所在作用範圍內所有可見的區域性變數(包括Lambda所在類的this),並且是值傳遞方式(相當於編譯器自動為我們按值傳遞了所有區域性變數),此時Lambda表示式中,實體預設為只讀的,在大括號內不能進行修改,如果想修改,可以用mutable修飾,如 [=]() mutable
[&] () {}
Lambda函式體內可以使用Lambda所在作用範圍內所有可見的區域性變數(包括Lambda所在類的this),並且是引用傳遞方式(相當於編譯器自動為我們按引用傳遞了所有區域性變數)
[this] () {}
函式體內可以使用Lambda所在類中的所有成員變數注意:儘量使用 = 而不使用 & ,以免造成記憶體問題
3.2、
QPushButton *b = new QPushButton(this);
connect(&b,&QPushButton::pressed,this,&MainWidget::close);
//Qt5引入了訊號槽的新語法:使用函式指標能夠獲得編譯期的型別檢查。
//Qt4版本訊號槽
connect(b,SIGNAL(pressed()),this,SLOT(close()));
- 1
- 2
- 3
- 4
- 5
- 6
- 訊號和槽的效率是非常高的,不過同真正的回撥函式比較起來,由於增加了靈活性,因此在速度上還是有所損失,追求高效率的實時系統中,應儘量少用;
- 訊號和槽機制和普通函式的呼叫相同,如果使用不當的話,在程式執行時也有可能產生死迴圈。
- 函式指標不能作為訊號或槽的引數
- 訊號和槽不能有預設引數
- 當訊號的傳送者為定時器時,儘量不要把connect函式放在if、while等可能會導致訊號槽阻塞的程式碼段裡面。我做過這樣一個事情:啟動程式時啟動定時器,用一個If語句判斷輸入是否合法,判斷通過則呼叫傳送者為定時器的connect函式,結果本該一分鐘觸發一次的槽函式在一秒內被連續觸發了十幾次;
- 當子執行緒中需要使用訊號槽機制時,必須在子執行緒標頭檔案中加巨集
Q_OBJECT
,當我們建立繼承於QThread的子執行緒時,這個巨集並不會自動新增。手動新增之後,構建專案可能會報錯:undefined reference to ‘vtable for’
,此時我們需要將子執行緒類從專案中移除(不要從磁碟上刪除),然後重新新增,QtCreator就會重新解析此類,再編譯就不再會出現上述錯誤. - 待續
--------------------- 作者:52_赫茲的鯨 來源:CSDN 原文:https://blog.csdn.net/qq_40194498/article/details/79647356?utm_source=copy 版權宣告:本文為博主原創文章,轉載請附上博文連結!