1. 程式人生 > >深入理解Qt訊號和槽機制、訊號和槽中的Lambda表示式

深入理解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 版權宣告:本文為博主原創文章,轉載請附上博文連結!