目录
- bool QObject::disconnect(const QObject *sender, const char *signal,
- const QObject *receiver, const char *method)
- {
- if (sender == 0 || (receiver == 0 && method != 0)) {
- qWarning("QObject::disconnect: Unexpected null parameter");
- return false;
- }
- const char *signal_arg = signal;
- QByteArray signal_name;
- bool signal_found = false;
- if (signal) {
- QT_TRY {
- signal_name = QMetaObject::normalizedSignature(signal);
- signal = signal_name.constData();
- } QT_CATCH (const std::bad_alloc &) {
- // if the signal is already normalized, we can continue.
- if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
- QT_RETHROW;
- }
- if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
- return false;
- signal++; // skip code
- }
- QByteArray method_name;
- const char *method_arg = method;
- int membcode = -1;
- bool method_found = false;
- if (method) {
- QT_TRY {
- method_name = QMetaObject::normalizedSignature(method);
- method = method_name.constData();
- } QT_CATCH(const std::bad_alloc &) {
- // if the method is already normalized, we can continue.
- if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
- QT_RETHROW;
- }
- membcode = extract_code(method);
- if (!check_method_code(membcode, receiver, method, "disconnect"))
- return false;
- method++; // skip code
- }
- /* We now iterate through all the sender's and receiver's meta
- * objects in order to also disconnect possibly shadowed signals
- * and slots with the same signature.
- */
- bool res = false;
- const QMetaObject *smeta = sender->metaObject();
- QByteArray signalName;
- QArgumentTypeArray signalTypes;
- Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
- if (signal)
- signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
- QByteArray methodName;
- QArgumentTypeArray methodTypes;
- Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
- if (method)
- methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
- do {
- int signal_index = -1;
- if (signal) {
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(
- &smeta, signalName, signalTypes.size(), signalTypes.constData());
- if (signal_index < 0)
- break;
- signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
- signal_index += QMetaObjectPrivate::signalOffset(smeta);
- signal_found = true;
- }
- if (!method) {
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, 0);
- } else {
- const QMetaObject *rmeta = receiver->metaObject();
- do {
- int method_index = QMetaObjectPrivate::indexOfMethod(
- rmeta, methodName, methodTypes.size(), methodTypes.constData());
- if (method_index >= 0)
- while (method_index < rmeta->methodOffset())
- rmeta = rmeta->superClass();
- if (method_index < 0)
- break;
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0);
- method_found = true;
- } while ((rmeta = rmeta->superClass()));
- }
- } while (signal && (smeta = smeta->superClass()));
- if (signal && !signal_found) {
- err_method_notfound(sender, signal_arg, "disconnect");
- err_info_about_objects("disconnect", sender, receiver);
- } else if (method && !method_found) {
- err_method_notfound(receiver, method_arg, "disconnect");
- err_info_about_objects("disconnect", sender, receiver);
- }
- if (res) {
- if (!signal)
- const_cast
(sender)->disconnectNotify(QMetaMethod()); - }
- return res;
- }
将对象发送者中的信号与对象接收者中的方法断开。 如果Connecton成功断开,则返回 true; 否则返回false。
当所涉及的任何一个对象被破坏时,都会删除信号槽连接。
disconnect() 通常以三种方式使用,如以下示例所示。
1.断开连接到对象信号的所有东西:
disconnect(myObject, nullptr, nullptr, nullptr);
等同于
myObject->disconnect();
2.断开连接到特定信号的所有东西
disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr);
等同于
myObject->disconnect(SIGNAL(mySignal()));
3.断开特定接收器
disconnect(myObject, nullptr, myReceiver, nullptr);
等同于
myObject->disconnect(myReceiver);
下面分析代码:
- if (signal) {
- QT_TRY {
- signal_name = QMetaObject::normalizedSignature(signal);
- signal = signal_name.constData();
- } QT_CATCH (const std::bad_alloc &) {
- // if the signal is already normalized, we can continue.
- if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
- QT_RETHROW;
- }
- if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
- return false;
- signal++; // skip code
- }
如果参数 signal不为空,则获取signal的名称。
- QByteArray method_name;
- const char *method_arg = method;
- int membcode = -1;
- bool method_found = false;
- if (method) {
- QT_TRY {
- method_name = QMetaObject::normalizedSignature(method);
- method = method_name.constData();
- } QT_CATCH(const std::bad_alloc &) {
- // if the method is already normalized, we can continue.
- if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
- QT_RETHROW;
- }
- membcode = extract_code(method);
- if (!check_method_code(membcode, receiver, method, "disconnect"))
- return false;
- method++; // skip code
- }
如果参数 method不为空,则获取method的名称。
接下来,遍历查找sender和receiver的meta objects.
- do {
- int signal_index = -1;
- if (signal) {
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(
- &smeta, signalName, signalTypes.size(), signalTypes.constData());
- if (signal_index < 0)
- break;
- signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
- signal_index += QMetaObjectPrivate::signalOffset(smeta);
- signal_found = true;
- }
- if (!method) {
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, 0);
- } else {
- const QMetaObject *rmeta = receiver->metaObject();
- do {
- int method_index = QMetaObjectPrivate::indexOfMethod(
- rmeta, methodName, methodTypes.size(), methodTypes.constData());
- if (method_index >= 0)
- while (method_index < rmeta->methodOffset())
- rmeta = rmeta->superClass();
- if (method_index < 0)
- break;
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0);
- method_found = true;
- } while ((rmeta = rmeta->superClass()));
- }
- } while (signal && (smeta = smeta->superClass()));
调用QMetaObjectPrivate::disconnect
- bool QMetaObjectPrivate::disconnect(const QObject *sender,
- int signal_index, const QMetaObject *smeta,
- const QObject *receiver, int method_index, void **slot,
- DisconnectType disconnectType)
- {
- if (!sender)
- return false;
- QObject *s = const_cast
(sender); - QBasicMutex *senderMutex = signalSlotLock(sender);
- QBasicMutexLocker locker(senderMutex);
- QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
- if (!scd)
- return false;
- bool success = false;
- {
- // prevent incoming connections changing the connections->receivers while unlocked
- QObjectPrivate::ConnectionDataPointer connections(scd);
- if (signal_index < 0) {
- // remove from all connection lists
- for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
- if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
- success = true;
- }
- } else if (signal_index < scd->signalVectorCount()) {
- if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
- success = true;
- }
- }
- locker.unlock();
- if (success) {
- scd->cleanOrphanedConnections(s);
- QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
- if (smethod.isValid())
- s->disconnectNotify(smethod);
- }
- return success;
- }
首先,获取ConnectionData *scd。
之后,根据scd移除相应的connections.
从函数QMetaObjectPrivate::disconnect返回, 返回值保存在res。
如果signal 或者 method 没找到,则提示错误。
- if (signal && !signal_found) {
- err_method_notfound(sender, signal_arg, "disconnect");
- err_info_about_objects("disconnect", sender, receiver);
- } else if (method && !method_found) {
- err_method_notfound(receiver, method_arg, "disconnect");
- err_info_about_objects("disconnect", sender, receiver);
- }
如果res的值为true,调用sender的disconnectNotify函数。
转储有关此对象的信号连接等信息用与调试输出。
- void QObject::dumpObjectInfo()
- {
- const_cast<const QObject *>(this)->dumpObjectInfo();
- }
- void QObject::dumpObjectInfo() const
- {
- qDebug("OBJECT %s::%s", metaObject()->className(),
- objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
- Q_D(const QObject);
- QBasicMutexLocker locker(signalSlotLock(this));
- // first, look for connections where this object is the sender
- qDebug(" SIGNALS OUT");
- QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
- if (cd && cd->signalVectorCount()) {
- QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
- for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
- const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
- if (!c)
- continue;
- const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
- qDebug(" signal: %s", signal.methodSignature().constData());
- // receivers
- while (c) {
- if (!c->receiver.loadRelaxed()) {
- qDebug("
" ); - c = c->nextConnectionList.loadRelaxed();
- continue;
- }
- if (c->isSlotObject) {
- qDebug("
" ); - c = c->nextConnectionList.loadRelaxed();
- continue;
- }
- const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
- const QMetaMethod method = receiverMetaObject->method(c->method());
- qDebug(" --> %s::%s %s",
- receiverMetaObject->className(),
- c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
- method.methodSignature().constData());
- c = c->nextConnectionList.loadRelaxed();
- }
- }
- } else {
- qDebug( "
" ); - }
- // now look for connections where this object is the receiver
- qDebug(" SIGNALS IN");
- if (cd && cd->senders) {
- for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
- QByteArray slotName = QByteArrayLiteral("
" ); - if (!s->isSlotObject) {
- const QMetaMethod slot = metaObject()->method(s->method());
- slotName = slot.methodSignature();
- }
- qDebug(" <-- %s::%s %s",
- s->sender->metaObject()->className(),
- s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
- slotName.constData());
- }
- } else {
- qDebug("
" ); - }
- }
首先,寻找这个对象是发送者的连接
然后,寻找这个对象是接收者的连接
将子树转储到调试输出。
- void QObject::dumpObjectTree()
- {
- const_cast<const QObject *>(this)->dumpObjectTree();
- }
- /*!
- Dumps a tree of children to the debug output.
- \note before Qt 5.9, this function was not const.
- \sa dumpObjectInfo()
- */
- void QObject::dumpObjectTree() const
- {
- dumpRecursive(0, this);
- }
-
- static void dumpRecursive(int level, const QObject *object)
- {
- if (object) {
- QByteArray buf;
- buf.fill(' ', level / 2 * 8);
- if (level % 2)
- buf += " ";
- QString name = object->objectName();
- QString flags = QLatin1String("");
- #if 0
- if (qApp->focusWidget() == object)
- flags += 'F';
- if (object->isWidgetType()) {
- QWidget * w = (QWidget *)object;
- if (w->isVisible()) {
- QString t("<%1,%2,%3,%4>");
- flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height());
- } else {
- flags += 'I';
- }
- }
- #endif
- qDebug("%s%s::%s %s", (const char*)buf, object->metaObject()->className(), name.toLocal8Bit().data(),
- flags.toLatin1().data());
- QObjectList children = object->children();
- if (!children.isEmpty()) {
- for (int i = 0; i < children.size(); ++i)
- dumpRecursive(level+1, children.at(i));
- }
- }
- }
递归输出object的meta信息。
缩进用了一个技巧:
- QByteArray buf;
- buf.fill(' ', level / 2 * 8);
- if (level % 2)
- buf += " ";
根据level层级,计算缩进大小。