信號槽是 Qt 框架引以為豪的機制之一。熟練使用和理解信號槽,能夠設計出解耦的非常漂亮的程序,有利於增強我們的技術設計能力。
所謂信號槽,實際就是觀察者模式。當某個事件發生之後,比如,按鈕檢測到自己被點擊了一下,它就會發出一個信號( signal)。這種發出是沒有目的的,類似廣播。如果有對象對這個信號感興趣,它就會使用連接( connect)函數,意思是,用自己的一個函數(稱為槽( slot))來處理這個信號。也就是說,當信號發出時,被連接的槽函數會自動被回調。這就類似觀察者模式:當發生了感興趣的事件,某一個操作就會被自動觸發。
在 Qt 5 中, QObject::connect()有幾個重載:
QMetaObject::Connection connect(const QObject *, const char *,const QObject *, const char *,Qt::ConnectionType);
QMetaObject::Connection connect(const QObject *, const QMetaMethod &,const QObject *, const QMetaMethod &,Qt::ConnectionType);
QMetaObject::Connection connect(const QObject *, const char *,const char *,Qt::ConnectionType) const;
QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,const QObject *, PointerToMemberFunction,Qt::ConnectionType)
QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,Functor);
返回值都是 QMetaObject::Connection。
connect()函數最常用的一般形式:connect(sender, signal, receiver, slot);
connect()一般會使用前面四個參數,第一個是發出信號的對象,第二個是發送對象發出的信號,第三個是接收信號的對象,第四個是接收對象在接收到信號之後所需要調用的函數。也就是說,當 sender 發出了 signal 信號之後,會自動調用 receiver的 slot 函數。
這是最常用的形式,我們可以套用這個形式去分析上面給出的五個重載。
第一個, sender 類型是 const QObject *, signal 的類型是 const char *, receiver 類型是 const QObject *,slot 類型是 const char *。這個函數將 signal 和 slot 作為字符串處理。
第二個, sender 和receiver 同樣是 const QObject *,但是 signal 和 slot 都是 const QMetaMethod &。我們可以將每個函數看做是 QMetaMethod 的子類。因此,這種寫法可以使用 QMetaMethod進行類型比對。
第三個, sender 同樣是 const QObject *, signal 和 slot 同樣是 const char*,但是卻缺少receiver。這個函數其實是將 this 指針作為 receiver。
第四個, sender 和receiver 也都存在,都是 const QObject *,但是 signal 和 slot 類型則是PointerToMemberFunction。看這個名字就應該知道,這是指向成員函數的指針。
第五個,前面兩個參數沒有什麼不同,最後一個參數是 Functor 類型。這個類型可以接受 static 函數、全局函數以及 Lambda 表達式。
由此我們可以看出, connect()函數, sender 和 receiver 沒有什麼區別,都是 QObject 指針;主要是 signal 和 slot 形式的區別。具體到我們的示例,我們的 connect()函數顯然是使用的第五個重載,最後一個參數是 QApplication 的 static 函數 quit()。也就是說,當我們的button 發出了 clicked()信號時,會調用 QApplication 的 quit()函數,使程序退出。
信號槽要求信號和槽的參數一致,所謂一致,是參數類型一致。如果不一致,允許的情況是,槽函數的參數可以比信號的少,即便如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是因為,你可以在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),但是不能說信號根本沒有這個數據,你就要在槽函數中使用(就是槽函數的參數比信號的多,這是不允許的)。
如果信號槽不符合,或者根本找不到這個信號或者槽函數的話,比如我們改成:
QObject::connect(&button, &QPushButton::clicked, &QApplication::quit2);
由於 QApplication 沒有 quit2 這樣的函數的,因此在編譯時,會有編譯錯誤:
'quit2' is not a member of QApplication
這樣,使用成員函數指針,我們就不會擔心在編寫信號槽的時候會出現函數錯誤。
而Qt4中connect函數的形式則是
QObject::connect(&button, SIGNAL(clicked()),&app, SLOT(quit()));使用了SIGNAL和SLOT宏。
Ubuntu 環境下Gtk與QT編譯環境安裝與配置 http://www.linuxidc.com/Linux/2013-08/88539.htm
Linux系統下QT環境搭建 http://www.linuxidc.com/Linux/2013-07/87576.htm
Ubuntu下QT控制台程序無法運行的解決方案以及XTerm的配置方法 http://www.linuxidc.com/Linux/2013-06/86244.htm
Ubuntu 10.04下QT4.7.4移植詳解 http://www.linuxidc.com/Linux/2013-01/77930.htm
Ubuntu 14.04下安裝部署Qt5開發環境 http://www.linuxidc.com/Linux/2014-05/101774.htm
Qt 的詳細介紹:請點這裡
Qt 的下載地址:請點這裡