QT信號槽連接


 

MOC

一:信號槽是什么?

Qt的信號和槽機制是Qt的一大特點,實際上這是和MFC中的消息映射機制相似的東西,要完成的事情也差不多,就是發送一個消息然后讓其它窗口響應,當然,這里的消息是廣義的說法,簡單點說就是如何在一個類的一個函數中觸發另一個類的另一個函數調用,而且還要把相關的參數傳遞過去.好像這和回調函數也有點關系,但是消息機制可比回調函數有用

 

二:Qt支持三種類型的信號-槽連接:
1,直接連接,當signal發射時,slot立即調用。此slot在發射signal的那個線程中被執行(不一定是接收對象生存的那個線程)
2,隊列連接,當控制權回到對象屬於的那個線程的事件循環時,slot被調用。此slot在接收對象生存的那個線程中被執行
3,自動連接(缺省),假如信號發射與接收者在同一個線程中,其行為如直接連接,否則,其行為如隊列連接。
連接類型可能通過以向connect()傳遞參數來指定。注意的是,當發送者與接收者生存在不同的線程中,而事件循環正運行於接收者的線程中,使用直接連接是不安全的。同樣的道理,調用生存在不同的線程中的對象的函數也是不是安全的。QObject::connect()本身是線程安全的。

用Qt寫Gui程序的時候,在main函數里面最后依據都是app.exec();很多書上對這句的解釋是,使Qt程序進入消息循環。  

當前connectionType為Qt::AutoConnection並且signal和slot不在一個線程或者是signal和不再當前線程中;或者是c->connectionType為 Qt::QueuedConnection這時候調用函數queued_activate:對參數轉換一下,然后調用QCoreApplication::postEvent
注意: postEvent第二個參數是QMetaCallEvent。
這樣這個signal-slot的connection就發送到receiver的消息隊列中去了。 

 

三:connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 
這里用到了兩個宏:SIGNAL() 和SLOT();通過connect聲明可以知道這兩個宏最后倒是得到一個const char*類型
在qobjectdefs.h中可以看到SIGNAL() 和SLOT()的宏定義:

#ifndef QT_NO_DEBUG 
# define QLOCATION "\0"__FILE__":"QTOSTRING(__LINE__) 
# define METHOD(a)   qFlagLocation("0"#a QLOCATION) 
# define SLOT(a)     qFlagLocation("1"#a QLOCATION) 
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION) 
#else 
# define METHOD(a)   "0"#a 
# define SLOT(a)     "1"#a 
# define SIGNAL(a)   "2"#a 
#endif 
所以這兩個宏的作用就是把函數名轉換為字符串並且在前面加上標識符

比如:SIGNAL(read())展開后就是"2read()";同理SLOT(read())展開后就是"1read()"。

connect(sender,SIGNAL(signal()),receiver,SLOT(slot())); 
實際上就是connect(sender,“2signal()”,receiver,“1slot())”; 

 

四:

# if defined(QT_NO_KEYWORDS)
#  define QT_NO_EMIT
# else
#   define slots
#   define signals protected
# endif
# define Q_SLOTS
# define Q_SIGNALS protected
# define Q_PRIVATE_SLOT(d, signature)
# define Q_EMIT
#ifndef QT_NO_EMIT
# define emit
#endif

signals宏有點不同,它限定Qt信號為protected方法,而slots宏可以是任意類型。

頭文件定義的public slots和signals對C++編譯器而言沒有意義,會被替換成public和protected。他們的真實意圖其實是給moc工具使用的,moc根據這些字符串關鍵字匹配,用來生成文件moc_Counter.cppQt源碼的構建過程是先moc轉換然后再執行C++編譯器。moc的目的是展開信號和槽,生成一個能讓編譯器讀懂的源文件

 

五:MOC元數據

Q_OBJECT創建QMetaObejct元對象數據成員:用來做信號槽的二維表。對於某一個信號,在二維表中存放着這個信號對應的槽的函數指針。依據這個信號的名字去查詢二維表,找到對應的槽的函數指針並進行調用

 

Qt的信號槽機制其實就是按照名稱查表,因此這里的首要問題是如何構造這個表?和C++虛函數表機制類似的,在Qt中,這個表就是元數據表

不過Qt似乎還沒有完全發揮元數據的能力,動態屬性,反射之類的機制

一般是通過宏Q_OBJECT定義的(內省函數
#define Q_OBJECT / 
public: / 
    static const QMetaObject staticMetaObject; / 
    virtual const QMetaObject *metaObject() const; / 
    virtual void *qt_metacast(const char *); / 
    QT_TR_FUNCTIONS / 
    virtual int qt_metacall(QMetaObject::Call, int, void **); / 
private: 

這里的三個虛函數metaObject,qt_metacast,qt_metacall是在moc文件中定義的
staticMetaObject是 QMetaObject對象,因為需要給屬於同一類的全部實例共享,所以它是靜態的。得到元數據表指針
metaObject方法僅僅返回staticMetaObject。
QT_TR_FUNCTIONS是一個用於所有tr函數的宏,用來實現多語言支持。
qt_metacast用於按照類名或它的某個基類名 進行動態轉換(dynamic cast)【Qt顯然不依賴運行時類型檢查(RTTI)】。
qt_metacall通過索引查表調用內部信號和槽參數由一個指向指針數組的指針進行傳遞,並在調用方法時進行適當的轉換

 

用戶設計的類可以從多個類派生,但只能擁有一個QObject(或從它派生)基類,這同時也是超類
class ConvDialog : public QDialog, private Ui::ConvDialog
{
    Q_OBJECT
Moc將產生以下代碼:
const QMetaObject ConvDialog::staticMetaObject = {
    { &QDialog::staticMetaObject, qt_meta_stringdata_ConvDialog,
      qt_meta_data_ConvDialog, 0 }
};
如果在QDialog前先繼承Ui::ConvDialog,moc將會生成:
const QMetaObject ConvDialog::staticMetaObject = {
    { &Ui::ConvDialog::staticMetaObject, qt_meta_stringdata_ConvDialog,
      qt_meta_data_ConvDialog, 0 }
};
這是錯誤的,因為Ui::ConvDialog不是QObject的一個派生類,由此不擁有staticMetaObject成員,這樣做只會導致一個編譯錯誤。

 

QMetaObject中的結構體d

struct{
        const QMetaObject *superdata;//這是元數據代表的類的基類的元數據
        const char *stringdata;//這是元數據的簽名標記
        const uint *data;//這是元數據的索引數組的指針
        const QMetaObject **extradata;//這是擴展元數據表的指針,一般是不用的 
}d;


第一個參數:QMetaObject類指針,指向父Qt元數據類。

第三個參數:無符號整型數組,這個數組是一個表,包含所有元數據的偏移、特征等等。所以,如果你想枚舉一個類的信號和槽,那就應該遍歷這個表,通過偏移量從stringdata數組中獲得方法名。

 

 

參考文章:http://blog.csdn.net/tingsking18/article/details/4991563

http://www.cnblogs.com/findumars/p/4851262.html

http://www.pediy.com/kssd/pediy12/133181.html

http://www.devbean.net/2012/12/how-qt-signals-and-slots-work/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM