深入理解QT的SIGNAL\SLOT機制(五):信號的發射過程

我們來看信號的發起過程,先來看一個宏定義:# define emit,這個宏定義將emit定義爲空,也就是說你在emit mysignal()的時候,這行代碼其實就是mysignal(),所以信號就是函數,只是換了個概念而已!
廢話不多說,來DEBUG:
這裏寫圖片描述
我們在11行打斷點F11進入:

// SIGNAL 0
void MyWidget::mysignal()
{
    QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

居然直接調用了moc文件中的mysignal函數,現在是不是更清楚信號就是函數了啊?這裏的this是MyWidget對象,staticMetaObject就是第二章提到的靜態QMEtaObject,其餘都是空。進入active函數之前回去先計算偏移量:
這裏寫圖片描述
822~824行:將QMetaObject的所有父類偏移量加起來,目的是找到子類的第一個信號的偏移量(5.9.1中除了類名信息之外,只存儲了信號和槽的信息)。現在進入active函數:
這裏寫圖片描述
3636行:子類第一個信號的偏移量+當前偏移量,就是我們需要的mysignal信號的偏移量。
3637~3660行:進行安全檢查,檢查是否綁定信號和槽。
接着來看:
這裏寫圖片描述
3694行:根據信號的signal_index下標查找到connectionList,這個connectionList存儲的是所有綁定到該信號的槽函數信息;
這裏寫圖片描述
3700~3705行:拿到列表的first和last,進行遍歷。
3707~3709行:receiver是空,就意味着沒有槽函數,continue;
3712~3721行:針對不同類型進行不同的處理;
我們的是在統一個線程中,調用3743行的switchSender函數,不同線程的是放到隊列中去;
這裏寫圖片描述
來看switchSender函數:

 inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id)
    {
        this->receiver = receiver;
        currentSender.sender = sender;
        currentSender.signal = signal_absolute_id;
        currentSender.ref = 1;
        previousSender = QObjectPrivate::setCurrentSender(receiver, &currentSender);
        switched = true;
    }

發現該函數基本是進行值拷貝,繼續來看active函數:
3757~3766行:如果c->callFunction不爲空,並且c->methodOffset在QMetaObject的methodOffset之內(保證調用的函數偏移量不超過QMetaObject的偏移量),就可以調用callFunction.
我們看到const auto callFunction = c->callFunction;
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
實際上就是在調用callFunction,也就是moc_test.cpp中的qt_static_metacall函數。
調用完之後繼續執行do{}while(),知道所有的槽被調用。

接下來按F11,進入callFunction
這裏寫圖片描述
可以看到確實調用了moc_test.cpp中的static_metacall函數,
71行:格局傳入的id調用對應的槽函數,所以myslot被調用。
OK,完結撒花!
如有問題歡迎指正


電子科技大學
胡力衛
[email protected]

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