信號槽是 Qt 框架引覺得豪的機制之一。c++
所謂信號槽,實際就是觀察者模式。當某個事件發生以後,好比,按鈕檢測到本身被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,相似廣播。若是有對象對這個信號感興趣,它就會使用鏈接(connect)函數,意思是,用本身的一個函數(成爲槽(slot))來處理這個信號。也就是說,當信號發出時,被鏈接的槽函數會自動被回調。這就相似觀察者模式:當發生了感興趣的事件,某一個操做就會被自動觸發。(這裏提一句,Qt 的信號槽使用了額外的處理來實現,並非 GoF 經典的觀察者模式的實現方式。)app
爲了體驗一下信號槽的使用,咱們以一段簡單的代碼說明:框架
// !!! Qt 5 #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Quit"); QObject::connect(&button, &QPushButton::clicked, &QApplication::quit); button.show(); return app.exec(); }
咱們按照前面文章中介紹的在 Qt Creator 中建立工程的方法建立好工程,而後將main()
函數修改成上面的代碼。點擊運行,咱們會看到一個按鈕,上面有「Quit」字樣。點擊按鈕,程序退出。函數
在 Qt 5 中,QObject::connect()
有五個重載:ui
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()
函數最經常使用的通常形式:this
// !!! Qt 5 connect(sender, signal, receiver, slot);
這是咱們最經常使用的形式。connect()
通常會使用前面四個參數,第一個是發出信號的對象,第二個是發送對象發出的信號,第三個是接收信號的對象,第四個是接收對象在接收到信號以後所須要調用的函數。也就是說,當 sender 發出了 signal 信號以後,會自動調用 receiver 的 slot 函數。.net
這是最經常使用的形式,咱們能夠套用這個形式去分析上面給出的五個重載。第一個,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()
函數,使程序退出。code
信號槽要求信號和槽的參數一致,所謂一致,是參數類型一致。若是不一致,容許的狀況是,槽函數的參數能夠比信號的少,即使如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是由於,你能夠在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),可是不能說信號根本沒有這個數據,你就要在槽函數中使用(就是槽函數的參數比信號的多,這是不容許的)。對象
藉助 Qt 5 的信號槽語法,咱們能夠將一個對象的信號鏈接到 Lambda 表達式,例如:
// !!! Qt 5 #include <QApplication> #include <QPushButton> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Quit"); QObject::connect(&button, &QPushButton::clicked, [](bool) { qDebug() << "You clicked me!"; }); button.show(); return app.exec(); }
注意這裏的 Lambda 表達式接收一個 bool 參數,這是由於QPushButton
的clicked()
信號其實是有一個參數的。Lambda 表達式中的qDebug()
相似於cout
,將後面的字符串打印到標準輸出。若是要編譯上面的代碼,你須要在 pro 文件中添加這麼一句:
QMAKE_CXXFLAGS += -std=c++0x
而後正常編譯便可。
該文章轉載自博客www.devbean.net,做者devbean