Qt 信號和槽函數

信號和槽是一種高級接口,應用於對象之間的通訊,它是 QT 的核心特性。當某個信號被髮射,就須要調用與之相綁定的槽函數。這與Windows下的消息機制相似,消息機制是基於回調函數。一個回調便是一個函數的指針,所以若是但願一個處理函數通知一些事件,能夠傳遞一個函數(回調函數)的指針給這個處理函數。這個處理函數就會在適當的時候調用回調函數。可是回調函數有兩大缺點:第一,它們不是類型安全的。咱們歷來不敢肯定處理函數會用正確的參數來調用回調函數;第二,回調函數被強力和處理函數聯繫着,由於處理函數必須知道去調用哪一個回調函數。編程

信號和槽的機制是類型安全的:一個信號的簽名必須與接收槽的簽名相匹配。(實際上一個槽可能有一個比它所接收到的信號的簽名更短的簽名由於它可以忽略額外的參數。)由於簽名是一致的,因此編譯器可以幫助咱們發現類型不匹配。信號和槽是鬆散的聯繫在一塊兒的:一個發射信號的類歷來不知道也不關心哪一個槽接收這個信號。Qt的信號和槽機制確保若是你將一個信號和一個槽鏈接起來,這個槽將在正確的時間被用這個信號的參數所調用。信號和槽能夠帶任何數量任何類型的參數。它們徹底是類型安全的。安全

信號(Signals)

當對象改變其狀態時,信號就由該對象發射 (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);
}

槽函數(Slots)

槽和普通的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;
}

關聯信號和槽(connect)

可使用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)

當信號和槽沒有必要繼續保持鏈接時,能夠經過調用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);

應注意的問題

  1. 信號與槽機制與普通函數的調用同樣,若是使用不當的話,在程序執行時也有可能產生死循環。所以,在定義槽函數時必定要注意避免間接造成無限循環,即在槽中再次發射所接收到的一樣信號。例如 , 在前面給出的例子中若是在 mySlot() 槽函數中加上語句 emit mySignal() 便可造成死循環。
  2. 若是一個信號與多個槽相聯繫的話,那麼,當這個信號被髮射時,與之相關的槽被激活的順序將是隨機的。
  3. 宏定義不能用在 signal 和 slot 的參數中。
  4. 信號和槽的參數個數與類型必須一致。
相關文章
相關標籤/搜索