信號和槽是一種高級接口,應用於對象之間的通訊,它是 QT 的核心特性。當某個信號被髮射,就須要調用與之相綁定的槽函數。這與Windows下的消息機制相似,消息機制是基於回調函數。一個回調便是一個函數的指針,所以若是但願一個處理函數通知一些事件,能夠傳遞一個函數(回調函數)的指針給這個處理函數。這個處理函數就會在適當的時候調用回調函數。可是回調函數有兩大缺點:第一,它們不是類型安全的。咱們歷來不敢肯定處理函數會用正確的參數來調用回調函數;第二,回調函數被強力和處理函數聯繫着,由於處理函數必須知道去調用哪一個回調函數。編程
信號和槽的機制是類型安全的:一個信號的簽名必須與接收槽的簽名相匹配。(實際上一個槽可能有一個比它所接收到的信號的簽名更短的簽名由於它可以忽略額外的參數。)由於簽名是一致的,因此編譯器可以幫助咱們發現類型不匹配。信號和槽是鬆散的聯繫在一塊兒的:一個發射信號的類歷來不知道也不關心哪一個槽接收這個信號。Qt的信號和槽機制確保若是你將一個信號和一個槽鏈接起來,這個槽將在正確的時間被用這個信號的參數所調用。信號和槽能夠帶任何數量任何類型的參數。它們徹底是類型安全的。安全
當對象改變其狀態時,信號就由該對象發射 (emit) 出去,並且對象只負責發送信號,它不知道另外一端是誰在接收這個信號。這樣就作到了真正的信息封裝,能確保對象被看成一個真正的軟件組件來使用。函數
信號只須要在頭文件中進行聲明,不須要在cpp中實現。放在Qt自定義關鍵字signals下,在此以前必定要加上Q_OBJECT宏。spa
在編程中,通常使用的是控件內部定義好的信號。如:QTreeWidget類下的 Signals:指針
void currentItemChanged ( QTreeWidgetItem * current, QTreeWidgetItem * previous ); void itemActivated ( QTreeWidgetItem * item, int column ); void itemChanged ( QTreeWidgetItem * item, int column ); void itemClicked ( QTreeWidgetItem * item, int column ); void itemCollapsed ( QTreeWidgetItem * item ); void itemDoubleClicked ( QTreeWidgetItem * item, int column ); void itemEntered ( QTreeWidgetItem * item, int column ); void itemExpanded ( QTreeWidgetItem * item ); void itemPressed ( QTreeWidgetItem * item, int column ); void itemSelectionChanged ();
也能夠自定義信號,並經過emit在代碼中發射信號。code
class sender : public QObject { Q_OBJECT public: void doSend(); signals: void send(int); }; // ------------ sender.cpp ----------- #include "sender.h" void sender :: doSend() { emit send(40); }
槽和普通的C++成員函數幾乎是同樣的(能夠是虛函數,能夠被重載,能夠是public slots、protected slots、private slots,能夠被其餘C++成員函數直接調用;惟一不一樣的是:槽還能夠和信號鏈接在一塊兒,在這種狀況下,信號被髮射時,會自動調用這個槽。)槽不須要信號傳過來的參數時,能夠不要參數;但槽一旦要參數,其參數個數,類型,順序必需要和對應的信號保持一致。另外,槽的參數不能有缺省值。xml
class receiver : public QObject { Q_OBJECT public slots: //帶有參數的槽函數,需和綁定的信號的參數保持一致 void recv(int); }; // ------------ Receiver.cpp ----------- void receiver :: recv(int n) { qDebug()<<"recv number: "<<n<<endl; }
可使用QObject類的靜態成員函數connect來創建信號的槽的關聯對象
bool QObject::connect (const QObject * sender, const char * signal, const QObject * receiver, const char * slot) [static]
具體的調用爲:connect(sender, SIGNAL(signal), receiver, SLOT(slot)); 其中sender和receiver爲QObject類對象的指針; SIGNAL宏和SLOT宏將信號的槽轉換成字符串。blog
sender s; receiver r; QObject::connect(&s, SIGNAL(send(int)), &r, SLOT(recv(int)));
注:在connect函數中信號函數和槽函數如有參數,只能寫出參數類型,而不能也將變量名寫出;不然,鏈接會失敗!接口
當信號發射時,會以不肯定的順序一個接一個的調用各個槽。
即不管是哪個信號被髮射,都會調用這個槽。
發射第一個信號時,也會發射第二個信號。
當信號和槽沒有必要繼續保持鏈接時,能夠經過調用disconnect來斷開它們。
bool QObject::disconnect (const QObject * sender, const char * signal, const Object * receiver, const char * slot) [static]
有三種狀況必須使用 disconnect() 函數:
(1)斷開與某個對象相關聯的任何對象。
disconnect(sender, 0, 0, 0) ; //或者 sender->disconnect();
(2)斷開與某個特定信號的任何關聯。
disconnect(sender, SIGNAL(signal()), 0, 0); //或者 sender->disconnect(SIGNAL(signal()));
(3)斷開兩個對象之間的關聯。
disconnect(sender, 0, receiver, 0); //或者 sender->disconnect(receiver);