【Qt筆記】信號槽

信號槽是 Qt 框架引覺得豪的機制之一。c++

所謂信號槽,實際就是觀察者模式。當某個事件發生以後,好比,按鈕檢測到本身被點擊了一下,它就會發出一個信號(signal)。這種發出是沒有目的的,相似廣播。若是有對象對這個信號感興趣,它就會使用鏈接(connect)函數,意思是,用本身的一個函數(成爲槽(slot))來處理這個信號。也就是說,當信號發出時,被鏈接的槽函數會自動被回調。這就相似觀察者模式:當發生了感興趣的事件,某一個操做就會被自動觸發。(這裏提一句,Qt 的信號槽使用了額外的處理來實現,並非 GoF 經典的觀察者模式的實現方式。)app

爲了體驗一下信號槽的使用,咱們以一段簡單的代碼說明:框架

// !!! Qt 5
#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton button("Quit");
    QObject::connect(&button, &QPushButton::clicked, &QApplication::quit);
    button.show();

    return app.exec();
}

咱們按照前面文章中介紹的在 Qt Creator 中建立工程的方法建立好工程,而後將main()函數修改成上面的代碼。點擊運行,咱們會看到一個按鈕,上面有「Quit」字樣。點擊按鈕,程序退出。函數

在 Qt 5 中,QObject::connect()有五個重載:ui

QMetaObject::Connection connect(const QObject *, const char *,
                                const QObject *, const char *,
                                Qt::ConnectionType);

QMetaObject::Connection connect(const QObject *, const QMetaMethod &,
                                const QObject *, const QMetaMethod &,
                                Qt::ConnectionType);

QMetaObject::Connection connect(const QObject *, const char *,
                                const char *,
                                Qt::ConnectionType) const;

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
                                const QObject *, PointerToMemberFunction,
                                Qt::ConnectionType)

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,
                                Functor);

這五個重載的返回值都是QMetaObject::Connection,如今咱們不去關心這個返回值。下面咱們先來看看connect()函數最經常使用的通常形式:this

// !!! Qt 5
connect(sender,   signal,
        receiver, slot);

這是咱們最經常使用的形式。connect()通常會使用前面四個參數,第一個是發出信號的對象,第二個是發送對象發出的信號,第三個是接收信號的對象,第四個是接收對象在接收到信號以後所須要調用的函數。也就是說,當 sender 發出了 signal 信號以後,會自動調用 receiver 的 slot 函數。.net

這是最經常使用的形式,咱們能夠套用這個形式去分析上面給出的五個重載。第一個,sender 類型是const QObject *,signal 的類型是const char *,receiver 類型是const QObject *,slot 類型是const char *。這個函數將 signal 和 slot 做爲字符串處理。第二個,sender 和 receiver 一樣是const QObject *,可是 signal 和 slot 都是const QMetaMethod &。咱們能夠將每一個函數看作是QMetaMethod的子類。所以,這種寫法可使用QMetaMethod進行類型比對。第三個,sender 一樣是const QObject *,signal 和 slot 一樣是const char *,可是卻缺乏了 receiver。這個函數實際上是將 this 指針做爲 receiver。第四個,sender 和 receiver 也都存在,都是const QObject *,可是 signal 和 slot 類型則是PointerToMemberFunction。看這個名字就應該知道,這是指向成員函數的指針。第五個,前面兩個參數沒有什麼不一樣,最後一個參數是Functor類型。這個類型能夠接受 static 函數、全局函數以及 Lambda 表達式。指針

由此咱們能夠看出,connect()函數,sender 和 receiver 沒有什麼區別,都是QObject指針;主要是 signal 和 slot 形式的區別。具體到咱們的示例,咱們的connect()函數顯然是使用的第五個重載,最後一個參數是QApplication的 static 函數quit()。也就是說,當咱們的 button 發出了clicked()信號時,會調用QApplicationquit()函數,使程序退出。code

信號槽要求信號和槽的參數一致,所謂一致,是參數類型一致。若是不一致,容許的狀況是,槽函數的參數能夠比信號的少,即使如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是由於,你能夠在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),可是不能說信號根本沒有這個數據,你就要在槽函數中使用(就是槽函數的參數比信號的多,這是不容許的)。對象

藉助 Qt 5 的信號槽語法,咱們能夠將一個對象的信號鏈接到 Lambda 表達式,例如:

// !!! Qt 5
#include <QApplication>
#include <QPushButton>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton button("Quit");
    QObject::connect(&button, &QPushButton::clicked, [](bool) {
        qDebug() << "You clicked me!";
    });
    button.show();

    return app.exec();
}

注意這裏的 Lambda 表達式接收一個 bool 參數,這是由於QPushButtonclicked()信號其實是有一個參數的。Lambda 表達式中的qDebug()相似於cout,將後面的字符串打印到標準輸出。若是要編譯上面的代碼,你須要在 pro 文件中添加這麼一句:

QMAKE_CXXFLAGS += -std=c++0x

而後正常編譯便可。

 

該文章轉載自博客www.devbean.net,做者devbean

相關文章
相關標籤/搜索