前面說了Qt最基本的實例建立、控件以及工具集的介紹,至關於對於Qt有了一個初次的認識,此次咱們開始認識Qt信號通訊的重點之一——信號槽。架構
信號槽是 Qt 框架引覺得豪的機制之一。熟練使用和理解信號槽,可以設計出解耦的很是漂亮的程序,有利於加強咱們的技術設計能力。app
所謂信號槽,實際就是觀察者模式。當某個事件發生以後,好比,按鈕檢測到本身被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,相似廣播。若是有對象對這個信號感興趣,它就會使用鏈接(connect)函數,意思是,用本身的一個函數(成爲槽(slot))來處理這個信號。也就是說,當信號發出時,被鏈接的槽函數會自動被回調。這就相似觀察者模式:當發生了感興趣的事件,某一個操做就會被自動觸發。(這裏提一句,Qt 的信號槽使用了額外的處理來實現,並非 GoF 經典的觀察者模式的實現方式。)框架
1 #include "slottest.h" 2 #include <QtWidgets/QApplication> 3 #include <QPushButton> 4 int main(int argc, char *argv[]) 5 { 6 QApplication a(argc, argv); 7 8 QPushButton button("Quit"); 9 QObject::connect(&button,&QPushButton::clicked,&QApplication::quit); 10 button.show(); 11 //slottest w; 12 //w.show(); 13 return a.exec(); 14 }
咱們開始一步一步的分析這短短的幾行代碼。第6行聲明一個QApplication類的對象,用於程序的啓動和調用;第8行聲明瞭一個按鈕控件QPushButton類的對象,用於產生一個按鈕,並傳遞一個字符串「Quit」命名控件顯示的名稱;第9行用到了QObject中的connect函數,咱們先來看這個函數的定義。ide
1 /*Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns a handle to the connection that can be used to disconnect it later. 2 3 You must use the SIGNAL() and SLOT() macros when specifying the signal and the method*/ 4 QMetaObject::Connection connect(const QObject *, const char *, 5 const QObject *, const char *, 6 Qt::ConnectionType); 7 8 QMetaObject::Connection connect(const QObject *, const QMetaMethod &, 9 const QObject *, const QMetaMethod &, 10 Qt::ConnectionType); 11 12 QMetaObject::Connection connect(const QObject *, const char *, 13 const char *, 14 Qt::ConnectionType) const; 15 16 QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, 17 const QObject *, PointerToMemberFunction, 18 Qt::ConnectionType) 19 20 QMetaObject::Connection connect(const QObject *, PointerToMemberFunction, 21 Functor);
從上面能夠看到,connect函數一共有五個重載的版本,其中各個參數比較以後sender和receiver沒有什麼區別,都是QObject指針,主要是signal和slot形式的區別。再回到咱們的調用回來,咱們採用的是第五個重載,當咱們的Button發出了clicked信號時,會調用QApplication的quit函數,從而使程序退出。函數
對於信號和槽的要求是參數保持一致,這裏所說的一致是參數類型的一致。若是不一致,能夠是槽函數的參數能夠比信號的少,並且參數的順序必須保持一致。工具
將上述代碼稍加修改,使用lambda表達式後咱們再來看一下效果。ui
1 QObject::connect(&button, &QPushButton::clicked,/*&QApplication::quit*/[](){qDebug()<< "quit"; });
QWidget類是全部用戶界面對象的基類。 窗口部件是用戶界面的一個基本單元:它從窗口系統接收鼠標、鍵盤和其它事件,而且在屏幕上繪製本身。每個窗口部件都是矩形的,而且它們按Z軸順序排列。一個窗口部件能夠被它的父窗口部件或者它前面的窗口部件蓋住一部分。 spa
QMainWindow 類提供一個有菜單條、錨接窗口(例如工具條)和一個狀態條的主應用程序窗口。主窗口一般用在提供一個大的中央窗口部件(例如文本編輯或者繪製畫布)以及周圍 菜單、工具條和一個狀態條。QMainWindow經常被繼承,由於這使得封裝中央部件、菜單和工具條以及窗口狀態條變得更容易,當用戶點擊菜單項或者工具條按鈕時,槽會被調用。設計
QDialog類是對話框窗口的基類。對話框窗口是主要用於短時間任務以及和用戶進行簡要通信的頂級窗口。QDialog能夠是模態對話框也能夠是非模態對話框。QDialog支持擴展性而且能夠提供返回值。它們能夠有默認按鈕。QDialog也能夠有一個QSizeGrip在它的右下角,使用setSizeGripEnabled()。 指針
QDialog 是最普通的頂級窗口。一個不會被嵌入到父窗口部件的窗口部件叫作頂級窗口部件。一般狀況下,頂級窗口部件是有框架和標題欄的窗口(儘管使用了必定的窗口部件標記,建立頂級窗口部件時也可能沒有這些裝飾。)在Qt中,QMainWindow和不一樣的QDialog的子類是最普通的頂級窗口。
若是是頂級對話框,那就基於QDialog建立,若是是主窗體,那就基於QMainWindow,若是不肯定,或者有可能做爲頂級窗體,或有可能嵌入到其餘窗體中,則基於QWidget建立。
固然了,實際中,你還能夠基於任何其餘部件類來派生。看實際需求了,好比QFrame、QStackedWidget等等。
經過系統提供的connect函數可讓咱們鏈接系統信號和槽,可是你應該會想到咱們桐鄉能夠本身定製本身的信號槽,這也是Qt架構的設計思路,用於咱們設計解耦的程序。信號槽不是GUI模塊提供的,而是Qt核心特性之一,因此咱們一樣能夠在普通的控制檯程序中使用信號槽。
注意:我之因此將頭文件和源文件分開來寫,是由於moc在個人編譯器中必需要將其分開,否則就會報錯。
1 #include<QObject> 2 3 /////////////////newspaper.h 4 class Newsspaper :public QObject{ 5 6 Q_OBJECT 7 public: 8 Newsspaper(const QString& name) :m_name(name) 9 { 10 11 } 12 void send(); 13 signals: 14 void newPaper(const QString& name); 15 private: 16 QString m_name; 17 };
1 #include "newspaper.h" 2 3 void Newsspaper::send() 4 { 5 emit newPaper(m_name); 6 }
1 #include<QObject> 2 #include<QDebug> 3 4 class Reader :public QObject 5 { 6 Q_OBJECT 7 public: 8 Reader(); 9 void receiveNewspaper(const QString& name); 10 };
1 #include "reader.h" 2 3 Reader::Reader(){} 4 5 void Reader::receiveNewspaper(const QString& name) 6 { 7 qDebug() << "Receive Newspaper:" << name; 8 }
1 #include "slottest.h" 2 #include <QtWidgets/QApplication> 3 #include <QPushButton> 4 #include <QObject> 5 #include <QCoreapplication> 6 #include "newspaper.h" 7 #include "reader.h" 8 9 int main(int argc, char *argv[]) 10 { 11 QApplication a(argc, argv); 12 Newsspaper newspaper("NewsPaper A"); 13 Reader reader; 14 QObject::connect(&newspaper,&Newsspaper::newPaper,&reader,&Reader::receiveNewspaper); 15 newspaper.send(); 16 17 return a.exec(); 18 19 }
運行結果:
Receive Newspaper: "NewsPaper A"
根據代碼咱們對幾個重點進行解釋:一、Q_OBJECT是Qt的一個宏,可以使程序具備信號槽機制,由moc進行處理,會生成以moc爲開頭的文件,moc是一種預處理器;二、emit是Qt的另外一個宏,用於表示發射信號,使槽函數可以接受信號;三、使用connect函數進行信號槽的鏈接,槽函數在獲取到消息體和信號參數後作出相應,這裏就是響應打印消息。四、信號槽的機制相似於廣播,能夠參照廣播模式來理解代碼。五、使用 signals 標記信號函數,信號是一個函數聲明,返回 void,不須要實現函數代碼;六、槽函數是普通的成員函數,做爲成員函數,會受到 public、private、protected 的影響。
感謝你的耐心閱讀,若是有哪些地方錯誤,請提出來,謝謝!