Qt學習筆記:信號和槽機制

在GUI編程中,經常希望一個部件的狀態改變能夠引起另一個部件的注意,也就是實現部件之間的通信。傳統的方法是採用回調函數。回調(callback)的本質是將一個預先定義的函數通過函數指針的方式傳遞給另一個函數,讓它在合適的時候通過指針調用該函數。舉一個簡單的例子:

#include <stdio.h> 
void clicked(int k)
{
    printf("#%d: I'm clicked\n", k);
}

void kicked(int k)
{
    printf("#%d: I'm kicked\n", k);
}

void callback(void(*pt) (int k), int k)
{
    (*pt)(k);
}

int main()
{
    for (int i = 0; i<10; ++i)
    {
        if (i % 3 == 0)
        {
            callback(clicked, i);
        }
        else
        {
            callback(kicked, i);
        }
    }
    return 0;
}

回調函數存在的主要問題在於不保證傳入參數類型的正確性,所以不是類型安全的。而Qt採用了一種信號(signal)和槽(slot)的機制,替代回調函數,實現部件之間的通信。信號/槽是類型安全的,因爲信號和槽的函數簽名必須一致,否則編譯器就會報錯(實際上槽的簽名可能更短,它會忽略額外參數)。

所有包含信號/槽的類,都必須直接或間接繼承於QObject,並且在聲明時加上宏Q_OBJECT。在對象狀態改變時,信號就會產生,另一個對象具有接收該信號的槽,從而實現了兩個對象之間的通信。只要信號與槽的簽名匹配,就可以連接,而信號發出者不知道它的信號將由那些對象接收,同樣地,槽只知道接收到信號,不關心信號是誰發出的。如圖所示,一個信號可以連接多個槽,一個槽也可以接收多個信號。信號發出時,接收該信號的slot按照connect的順序,依次執行,直到所有的slot都返回,才繼續執行後面的程序。
這裏寫圖片描述

使用函數connect即可完成信號和槽的連接,如需解除連接,則使用disconnect函數

connect(scrollbar, SIGNAL(valueChanged(int)), mainwindow, SLOT(function(int)));

對於含有默認參數的信號和槽,例如:QObject::destroyed()和QObject::objectDestroyed()

void destroyed(QObject* = 0);//signal
void objectDestroyed(QObject* obj = 0);//slot

以下幾種連接方式均合法:

connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

但是以下這種連接不合法:

connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

在這種情況下,slot會等待signal傳遞一個QObject,但signal根本不會傳這樣一個參數過來,所以會引起一個runtime error。

Qt的信號/槽機制由Qt的元對象系統(meta-object system)支持,信號由元對象編譯工具(meta-object compiler, moc)自動定義,不能在.cpp文件中自己寫實現,也沒有任何返回值。Qt已經爲QObject及其子類預定義了一些信號,直接使用即可。而槽就是普通的函數,按照通常的函數定義和調用即可。

與回調相比,信號/槽比較靈活,但是沒有回調快。Qt文檔中的描述是:

In general, emitting a signal that is connected to some slots, is approximately ten times slower than calling the receivers directly, with non-virtual function calls.
(通常來說,發出一個到所連接槽的信號,大約比直接調用一個接收函數慢10倍)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章