我們來看信號的發起過程,先來看一個宏定義:# 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, ¤tSender);
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]