天天看點

Qt學習記錄--02 Qt的信号槽機制介紹(含Qt5與Qt4的差異對比)

一 閑談:

        熟悉Window下程式設計的小夥伴們,對其消息機制并不陌生, 話說:一切皆消息。它可以很友善實作不同窗體之間的通信,然而MFC庫将很多底層的消息都屏蔽了,盡管使使用者更加友善、簡易地處理消息,但也讓人特别是沒有Win32程式設計基的人感到迷茫,不是為何,筆者也是深受其害的。

        較長的描述就不在此展開,感興趣的請查閱浩瀚如海的資料。。。

二 簡要介紹:

        基于Qt開發,信号槽是確定正常通信的主要機制,特别是在多線程開發中,線程函數與界面的通信是無法直接進行的,會存在程式崩潰的問題,筆者在實際開發過程中也遇到過此問題,利用Qt的信号槽機制可以避免。

        所謂信号槽,類似于設計模式中的觀察者模式。當某一事件發生之後,比如,點選了一下PushButton,它就會發出一個信号(signal)。需注意,這種發出是沒有目的的,類似廣播。如果有對象對這個信号感興趣,可以使用連接配接(connect)函數進行兩者之間的關聯,即:發送者發送信号(signal),接收者(感興趣對象)用自己的一個函數(稱之為槽(slot))來處理這個信号。同觀察者一樣,一個signal可以關聯(注冊)多個slot,當信号發出時,被連接配接的槽函數會自動被回調。

        connect()函數是信号槽機制的關鍵,下面介紹。

三 connect()函數:

        Qt5與Qt4中對connect()函數的實作有所差異。

        首先,看Qt4對其實作的定義:

bool connect(const QObject *, const char *,
             const QObject *, const char *,
             Qt::ConnectionType);
 
bool connect(const QObject *, const QMetaMethod &,
             const QObject *, const QMetaMethod &,
             Qt::ConnectionType);
 
bool connect(const QObject *, const char *,
             const char *,
             Qt::ConnectionType) const
           

       介紹定義1,參數分别為:發送者sender、信号signal、接收者receiver和槽slot,最後一個基本不用。sender 類型是const QObject *,signal 的類型是const char *,receiver 類型是const QObject *,slot 類型是const char *。這個函數将 signal 和 slot 作為字元串處理。

        Qt4使用了SIGNAL和SLOT這兩個宏,将信号和槽的函數名轉換成了字元串。注意,不能将全局函數或者 Lambda 表達式傳入connect()。使用字元串導緻了Qt4有以下缺點:一旦出現連接配接不成功的情況,Qt 4 是沒有編譯錯誤的(因為一切都是字元串,編譯期是不檢查字元串是否比對),而是在運作時給出錯誤。這無疑會增加程式的不穩定性。

        下面,看Qt5對其實作的定義:

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);
           

        第一個,sender 類型是const QObject *,signal 的類型是const char *,receiver 類型是const QObject *,slot 類型是const char *。這個函數将 signal 和 slot 作為字元串處理,與Qt4相同,應該是為了相容性而予以保留的。

        第二個,sender 和 receiver 同樣是const QObject *,但是 signal 和 slot 都是const QMetaMethod &。我們可以将每個函數看做是QMetaMethod的子類。是以,這種寫法可以使用QMetaMethod進行類型比對。

        第三個,sender 同樣是const QObject *,signal 和 slot 同樣是const char *,但是卻缺少了 receiver。這個函數其實是将 this 指針作為 receiver,與Qt4相同,應該是為了相容性而予以保留的。

        第四個,sender 和 receiver 也都存在,都是const QObject *,但是 signal 和 slot 類型則是PointerToMemberFunction。看這個名字就應該知道,這是指向成員函數的指針。

       第五個,前面兩個參數沒有什麼不同,最後一個參數是Functor類型。這個類型可以接受 static 函數、全局函數以及 Lambda 表達式。

       Qt5相比較于Qt4的優勢是添加了第4和第5種的重載形式,使得Qt可以在編譯期進行錯誤檢查,及早發現問題。

在下一篇文章中将根據實際代碼簡要介紹信号槽的使用

繼續閱讀