QT封裝了具體操做系統的消息機制,遵循經典的GUI消息驅動事件模型。php
QT定義了與操做系統消息相關的本身的概念,即信號與槽。編程
信號signal是由操做系統產生的消息。安全
槽slot是程序中的消息處理函數。框架
connect將系統消息綁定到消息處理函數。ide
信號到槽的鏈接必須發生在兩個QT對象間。函數
bool QObject::connect ( const QObject * sender, //發生對象工具
const char * signal, //消息名測試
const QObject * receiver, //接收對象spa
const char *method, //接收對象的成員函數操作系統
Qt::ConnectionType type = Qt::AutoConnection )
在QT中消息使用字符串進行描述,connect函數在消息名和處理函數之間創建映射。
QT中的關鍵字
SIGNAL用於指定消息名
SLOT用於指定消息處理函數名
Q_OBJECT因此自定義槽的類必須在類聲明的開始處加上Q_OBJECT
slots用於在類中聲明消息處理函數
信號和槽機制是QT的核心機制,是一種高級接口,應用於QT對象之間的通訊,是QT的核心特性,也是QT區別於其它工具包的重要地方。信號和槽是QT自行定義的一種通訊機制,獨立於標準的C/C++語言,要正確的處理信號和槽,必須藉助一個稱爲moc(Meta Object Compiler)的QT工具,MOC工具是一個C++預處理程序,爲高層次的事件處理自動生成所須要的附加代碼。
在QT中信號和槽取代了傳統GUI框架中的回調函數,信號和槽能攜帶任意數量和任意類型的參數,是類型徹底安全的。全部從QObject或其子類(如Qwidget)派生的類都可以包含信號和槽。當對象改變其狀態時,信號就由對象發射(emit)出去,但對象不知道另外一端是誰在接收信號。槽用於接收信號,但槽是普通的對象成員函數。一個槽並不知道是否有任何信號與本身相鏈接,並且對象並不瞭解具體的通訊機制。
當某個信號對其客戶或全部者發生的內部狀態發生改變,信號被一個對象發射。只有定義過這個信號的類及其派生類可以發射這個信號。當一個信號被髮射時,與其相關聯的槽將被馬上執行,就象一個正常的函數調用同樣。信號-槽機制徹底獨立於任何GUI事件循環。只有當全部的槽返回之後發射函數(emit)才返回。 若是存在多個槽與某個信號相關聯,當這個信號被髮射時,這些槽將會一個接一個地執行,但執行的順序將會是隨機的,不能人爲地指定哪一個先執行、哪一個後執行。
信號的聲明是在頭文件中進行的,QT的signals關鍵字指出進入了信號聲明區,隨後便可聲明本身的信號。
signals:
void overflow();
signals是QT的關鍵字,而非C/C++的。信號能夠重載,但信號卻沒有函數體定義,而且信號的返回類型都是void,不要期望能從信號返回什麼有用信息。
信號由moc自動產生,不該該在.cpp文件中實現。
槽是普通的C++成員函數,能夠被正常調用,惟一的特殊性就是不少信號能夠與其相關聯。當與其關聯的信號被髮射時,信號關聯的槽就會被調用。槽能夠有參數,但槽的參數不能有缺省值。
槽是普通的成員函數,也有訪問權限。槽的訪問權限決定了誰可以與其相關聯。同普通的C++成員函數同樣,槽函數也分爲三種類型,即public slots、private slots和protected slots。
public slots:使用publicslots聲明的槽表示任何對象均可將信號與之相鏈接。在組件編程中,能夠建立彼此互不瞭解的對象,將它們的信號與槽進行鏈接以便信息可以正確的傳遞。
protected slots:使用protected slots聲明的槽表示當前類及其子類能夠將信號與之相鏈接。適用於那些槽,它們是類實現的一部分,可是其界面接口卻面向外部。
private slots:使用private slots聲明的槽表示只有類本身能夠將信號與之相鏈接,適用於聯繫很是緊密的類。
槽也可以聲明爲虛函數。
槽的聲明也是在頭文件中進行的。
public slots:
void setValue(int value);
自定義槽
只有QObject的子類才能自定義槽
定義槽的類必須在類聲明的最開始處使用Q_OBJECT
類中聲明槽是須要使用slots關鍵字
槽與所處理的信號在函數簽名上必須一致
SIGNAL與SLOT指定的名稱中能夠包含參數類型,不能包含具體的參數名
錯誤Object::connect:No such slot
A、檢查類對象是否繼承自QObject
B、檢查類聲明的開始處是否添加Q_OBJECT
C、檢查是否使用slots對槽進行聲明
D、檢查槽的名稱偏斜是否錯誤
E、從新編譯工程
經過調用QObject對象的connect函數來將某個對象的信號與另一個對象的槽函數相關聯,當發射者對象發射信號時,接收者對象的槽函數將被調用。connect函數的定義以下:
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection )
connect函數的做用就是將發射者sender對象中的信號signal與接收者receiver中的method槽函數聯繫起來。當指定信號signal時必須使用QT的宏SIGNAL(),當指定槽函數時必須使用宏SLOT()。若是發射者與接收者屬於同一個對象的話,那麼在connect 調用中接收者參數能夠省略。
一個信號可以與另外一個信號相關聯,此時發射者發出信號後接收者的信號也會接着發射。
當信號與槽沒有必要繼續保持關聯時,可使用disconnect函數來斷開鏈接。
bool QObject::disconnect ( const QObject * sender, const char * signal, const QObject * receiver, const char *method )
disconnect函數斷開發射者中的信號與接收者中的槽函數之間的關聯。
在disconnect函數中0能夠用做一個通配符,分別表示任何信號、任何接收對象、接收對象中的任何槽函數。可是發射者sender不能爲0,其它三個參數的值能夠等於0。
如下三種狀況須要使用disconnect()函數斷開信號與槽的關聯:
A、斷開與某個對象相關聯的任何對象
disconnect(sender, 0, 0, 0);
sender->disconnect();
B、斷開與某個特定信號的任何關聯
disconnect(sender, SIGNAL(mySignal()), 0, 0);
sender->disconnect(SIGNAL(mySignal()));
C、斷開兩個對象之間的關聯
disconnect(sender, 0, receiver, 0);
sender->disconnect(receiver);
Qt利用信號與槽(signals/slots)機制取代傳統的callback來進行對象之間的溝通。當操做事件發生的時候,對象會發提交一個信號(signal);而槽(slot)則是一個函數接受特定信號而且運行槽自己設置的動做。信號與槽之間,則經過QObject的靜態方法connect來連接。
信號在任何運行點上皆可發射,甚至能夠在槽裏再發射另外一個信號,信號與槽的連接不限定爲一對一的連接,一個信號能夠連接到多個槽或多個信號連接到同一個槽,甚至信號也可鏈接到信號。
以往的callback缺少類型安全,在調用處理函數時,沒法肯定是傳遞正確型態的參數。但信號和其接受的槽之間傳遞的數據型態必需要相符合,不然編譯器會提出警告。信號和槽可接受任何數量、任何型態的參數,因此信號與槽機制是徹底類型安全。
信號與槽機制也確保了低耦合性,發送信號的類的並不知道是哪一個槽會接受,也就是說一個信號能夠調用全部可用的槽。此機制會確保當在"鏈接"信號和槽時,槽會接受信號的參數而且正確運行。
元對象編譯器moc(meta object compiler)對C++文件中的類聲明進行分析併產生用於初始化元對象的C++代碼,元對象包含所有信號和槽的名字以及指向槽函數的指針。
moc讀C++源文件,若是發現有Q_OBJECT宏聲明的類,就會生成另一個C++源文件,新生成的文件中包含有該類的元對象代碼。例如,假設咱們有一個頭文件mysignal.h,在這個文件中包含有信號或槽的聲明,那麼在編譯以前 moc 工具就會根據該文件自動生成一個名爲mysignal.moc.h的C++源文件並將其提交給編譯器;對應於mysignal.cpp文件moc工具將自動生成一個名爲mysignal.moc.cpp文件提交給編譯器。
元對象代碼是signal/slot機制所必須的。用moc產生的C++源文件必須與類實現一塊兒進行編譯和鏈接,或者用#include語句將其包含到類的源文件中。moc並不擴展#include或者#define宏定義,只是簡單的跳過所遇到的任何預處理指令。
信號和槽函數的聲明通常位於頭文件中,同時在類聲明的開始位置必須加上Q_OBJECT語句,Q_OBJECT語句將告訴編譯器在編譯以前必須先應用moc工具進行擴展。關鍵字signals是對信號的聲明,siganls沒有public、private、protected等屬性,slots是對槽函數的聲明,slots有public、private、protected等屬性。signals、slots關鍵字是QT 本身定義的,不是C++中的關鍵字。
信號的聲明相似於函數的聲明而非變量的聲明,左邊要有類型,右邊要有括號,若是要向槽中傳遞參數的話,在括號中指定每一個形式參數的類型,固然,形式參數的個數能夠多於一個。
關鍵字slots指出隨後開始槽的聲明,這裏slots用的也是複數形式。
槽的聲明與普通函數的聲明同樣,能夠攜帶零或多個形式參數。既然信號的聲明相似於普通C++函數的聲明,那麼,信號也可採用C++中虛函數的形式進 行聲明,即同名但參數不一樣。例如,第一次定義的void mySignal()沒有帶參數,而第二次定義的卻帶有參數,從這裏咱們能夠看到QT的信號機制是很是靈活的。
信號與槽之間的聯繫必須事先用connect函數進行指定。若是要斷開兩者之間的聯繫,可使用函數disconnect。
信號與槽是一種高效靈活的通訊機制,但有其缺陷:
A、信號與槽的很是高效的,可是與回調函數相比,因爲增長了靈活性,所以在速度上有所損失,這種損失相對來講是比較小的,經過在一臺i586-133的機器上測試是10微秒(運行Linux),可見這種機制所提供的簡潔性、靈活性仍是值得的。通常來講,在實時系統中就要儘量的少用信號與槽機制。
B、信號與槽機制與普通函數的調用同樣,若是使用不當的話,在程序執行時也有可能產生死循環。所以,在定義槽函數時必定要避免在槽函數中再次發射所接收到的一樣信號。
C、若是一個信號與多個槽相關聯,那麼當這個信號被髮射時,與之相關的槽函數被調用的順序將是隨機的。
D、宏定義不能用在信號和槽的參數中。
moc工具不擴展#define,在信號和槽的參數中使用宏將不能正確地工做,不帶參數是能夠的。
E、構造函數不能用在signals或者slots聲明區域內。
F、函數指針不能做爲信號或槽的參數。
函數指針做爲參數是不合語法,但可使用typedef將函數指針類型重命名,使用函數指針類型做爲參數是合語法的。
G、信號與槽不能有缺省參數。
H、信號與槽也不能使用模板類參數
可使用typedef重命名模板類,重命名後的類型名能夠做爲信號與槽的參數
I、嵌套的類不能位於信號或槽區域內,也不能有信號或者槽。
J、友元聲明不能位於信號或者槽聲明區內,應該在普通C++的private、protected或者public區內進行聲明。