6. Qt 信号与信号槽 (7)-QMetaObject:: activate
生活随笔
收集整理的這篇文章主要介紹了
6. Qt 信号与信号槽 (7)-QMetaObject:: activate
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
最后調(diào)用callFunction() 或者metaCall()
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) {// 這里得到的是QObject的數(shù)據(jù),首先判斷是否為阻塞設(shè)置if (sender->d_func()->blockSig)return;// 得到全局鏈表QConnectionList * const list = ::connectionList();if (!list)return;QReadLocker locker(&list->lock);void *empty_argv[] = { 0 };if (qt_signal_spy_callback_set.signal_begin_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index,argv ? argv : empty_argv);locker.relock();}// 在sender的哈希表中得到sender的連接QConnectionList::Hash::const_iterator it = list->sendersHash.find(sender);const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();if (it == end) {if (qt_signal_spy_callback_set.signal_end_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);locker.relock();}return;}QThread * const currentThread = QThread::currentThread();const int currentQThreadId = currentThread ? QThreadData::get(currentThread)->id : -1;// 記錄sender連接的索引QVarLengthArray<int> connections;for (; it != end && it.key() == sender; ++it) {connections.append(it.value());// 打上使用標(biāo)記,因?yàn)榭赡苁欠旁陉?duì)列中list->connections[it.value()].inUse = 1;}for (int i = 0; i < connections.size(); ++i) {const int at = connections.constData()[connections.size() - (i + 1)];QConnectionList * const list = ::connectionList();// 得到連接QConnection &c = list->connections[at];c.inUse = 0;if (!c.receiver || (c.signal < from_signal_index || c.signal > to_signal_index))continue;// 判斷是否放到隊(duì)列中// determine if this connection should be sent immediately or// put into the event queueif ((c.type == Qt::AutoConnection&& (currentQThreadId != sender->d_func()->thread|| c.receiver->d_func()->thread != sender->d_func()->thread))|| (c.type == Qt::QueuedConnection)) {::queued_activate(sender, c, argv);continue;}// 為receiver設(shè)置當(dāng)前發(fā)送者const int method = c.method;QObject * const previousSender = c.receiver->d_func()->currentSender;c.receiver->d_func()->currentSender = sender;list->lock.unlock();if (qt_signal_spy_callback_set.slot_begin_callback != 0)qt_signal_spy_callback_set.slot_begin_callback(c.receiver, method, argv ? argv : empty_argv); #if defined(QT_NO_EXCEPTIONS)c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); #elsetry {// 調(diào)用receiver的方法c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);} catch (...) {list->lock.lockForRead();if (c.receiver)c.receiver->d_func()->currentSender = previousSender;throw;} #endifif (qt_signal_spy_callback_set.slot_end_callback != 0)qt_signal_spy_callback_set.slot_end_callback(c.receiver, method);list->lock.lockForRead();if (c.receiver)c.receiver->d_func()->currentSender = previousSender;}if (qt_signal_spy_callback_set.signal_end_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);locker.relock();} }void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) {int signal_index = signalOffset + local_signal_index;/* 我們所做的第一件事,是快速檢查一個(gè) 64 位的位蒙版 bit-mask。如果為 0,* 我們就知道沒有連接到該信號(hào)的東西,可以迅速返回,* 這意味著,發(fā)送一個(gè)沒有與槽連接的信號(hào)是相當(dāng)迅速的。*/if (!sender->d_func()->isSignalConnected(signal_index))return; // nothing connected to these signals, and no spy/* ... 跳過調(diào)試信息和 QML 調(diào)用,以及一些合理性檢查 ... *//* 使用互斥鎖,因?yàn)?connectionList 中的所有操作都是線程安全的 */QMutexLocker locker(signalSlotLock(sender));/* 獲取該信號(hào)的 ConnectionList。此處做了一些簡(jiǎn)化。真實(shí)的代碼還為列表添加了引用計(jì)數(shù)和一些合理性檢查 */QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;const QObjectPrivate::ConnectionList *list =&connectionLists->at(signal_index);QObjectPrivate::Connection *c = list->first;if (!c) continue;// 我們需要最后一次檢查,確保在信號(hào)發(fā)出的過程中添加的信號(hào)不會(huì)在本次發(fā)出過程被觸發(fā)。QObjectPrivate::Connection *last = list->last;/* 遍歷槽 */do {if (!c->receiver)continue;QObject * const receiver = c->receiver;const bool receiverInSameThread = QThread::currentThreadId() == receiver->d_func()->threadData->threadId;// 確定該連接應(yīng)該立即發(fā)出,還是放入事件隊(duì)列if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)|| (c->connectionType == Qt::QueuedConnection)) {/* 從根本上說,就是復(fù)制參數(shù),發(fā)出事件 */queued_activate(sender, signal_index, c, argv);continue;} else if (c->connectionType == Qt::BlockingQueuedConnection) {/* ... 跳過 ... */continue;}/* 助手結(jié)構(gòu)體,設(shè)置 sender()(并且在超出作用域之后重新設(shè)回 */QConnectionSenderSwitcher sw;if (receiverInSameThread)sw.switchSender(receiver, sender, signal_index);const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;const int method_relative = c->method_relative;if (c->isSlotObject) {/* ... 跳過 ... Qt5 風(fēng)格的指向函數(shù)指針的連接 */} else if (callFunction && c->method_offset metaObject()->methodOffset()) {/* 如果存在 callFunction(指向由 moc 生成的 qt_static_metacall 的指針,* 調(diào)用該函數(shù)。還需要檢查已保存的 metodOffset 是否依舊可用* (因?yàn)槲覀兛赡茉谖鰳?gòu)函數(shù)中調(diào)用) */locker.unlock(); // 實(shí)際調(diào)用時(shí)不能持有鎖callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);locker.relock();} else {/* 動(dòng)態(tài)對(duì)象 */const int method = method_relative + c->method_offset;locker.unlock();metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);locker.relock();}// 檢查該對(duì)象是否被槽析構(gòu)if (connectionLists->orphaned) break;} while (c != last && (c = c->nextConnectionList) != 0); }總結(jié)
以上是生活随笔為你收集整理的6. Qt 信号与信号槽 (7)-QMetaObject:: activate的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6. Qt 信号与信号槽 (6)- QO
- 下一篇: Qt 原理-MOC(1)Meta Obj