Qt源码分析--QObject(4)

目录

1.static bool disconnect(const QObject *sender, const char *signal,const QObject *receiver, const char *member);

2.dumpObjectInfo()

3.dumpObjectTree()


1.static bool disconnect(const QObject *sender, const char *signal,const QObject *receiver, const char *member);
 

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<QObject*>(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<QObject *>(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函数。

2.dumpObjectInfo()

转储有关此对象的信号连接等信息用与调试输出。

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("          <Disconnected receiver>");
                    c = c->nextConnectionList.loadRelaxed();
                    continue;
                }
                if (c->isSlotObject) {
                    qDebug("          <functor or function pointer>");
                    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( "        <None>" );
    }
    // 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("<unknown>");
            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("        <None>");
    }
}

首先,寻找这个对象是发送者的连接

然后,寻找这个对象是接收者的连接

3.dumpObjectTree()

将子树转储到调试输出。

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层级,计算缩进大小。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值