• 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);
     

    1. bool QObject::disconnect(const QObject *sender, const char *signal,
    2. const QObject *receiver, const char *method)
    3. {
    4. if (sender == 0 || (receiver == 0 && method != 0)) {
    5. qWarning("QObject::disconnect: Unexpected null parameter");
    6. return false;
    7. }
    8. const char *signal_arg = signal;
    9. QByteArray signal_name;
    10. bool signal_found = false;
    11. if (signal) {
    12. QT_TRY {
    13. signal_name = QMetaObject::normalizedSignature(signal);
    14. signal = signal_name.constData();
    15. } QT_CATCH (const std::bad_alloc &) {
    16. // if the signal is already normalized, we can continue.
    17. if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
    18. QT_RETHROW;
    19. }
    20. if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
    21. return false;
    22. signal++; // skip code
    23. }
    24. QByteArray method_name;
    25. const char *method_arg = method;
    26. int membcode = -1;
    27. bool method_found = false;
    28. if (method) {
    29. QT_TRY {
    30. method_name = QMetaObject::normalizedSignature(method);
    31. method = method_name.constData();
    32. } QT_CATCH(const std::bad_alloc &) {
    33. // if the method is already normalized, we can continue.
    34. if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
    35. QT_RETHROW;
    36. }
    37. membcode = extract_code(method);
    38. if (!check_method_code(membcode, receiver, method, "disconnect"))
    39. return false;
    40. method++; // skip code
    41. }
    42. /* We now iterate through all the sender's and receiver's meta
    43. * objects in order to also disconnect possibly shadowed signals
    44. * and slots with the same signature.
    45. */
    46. bool res = false;
    47. const QMetaObject *smeta = sender->metaObject();
    48. QByteArray signalName;
    49. QArgumentTypeArray signalTypes;
    50. Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
    51. if (signal)
    52. signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
    53. QByteArray methodName;
    54. QArgumentTypeArray methodTypes;
    55. Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
    56. if (method)
    57. methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
    58. do {
    59. int signal_index = -1;
    60. if (signal) {
    61. signal_index = QMetaObjectPrivate::indexOfSignalRelative(
    62. &smeta, signalName, signalTypes.size(), signalTypes.constData());
    63. if (signal_index < 0)
    64. break;
    65. signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
    66. signal_index += QMetaObjectPrivate::signalOffset(smeta);
    67. signal_found = true;
    68. }
    69. if (!method) {
    70. res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, 0);
    71. } else {
    72. const QMetaObject *rmeta = receiver->metaObject();
    73. do {
    74. int method_index = QMetaObjectPrivate::indexOfMethod(
    75. rmeta, methodName, methodTypes.size(), methodTypes.constData());
    76. if (method_index >= 0)
    77. while (method_index < rmeta->methodOffset())
    78. rmeta = rmeta->superClass();
    79. if (method_index < 0)
    80. break;
    81. res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0);
    82. method_found = true;
    83. } while ((rmeta = rmeta->superClass()));
    84. }
    85. } while (signal && (smeta = smeta->superClass()));
    86. if (signal && !signal_found) {
    87. err_method_notfound(sender, signal_arg, "disconnect");
    88. err_info_about_objects("disconnect", sender, receiver);
    89. } else if (method && !method_found) {
    90. err_method_notfound(receiver, method_arg, "disconnect");
    91. err_info_about_objects("disconnect", sender, receiver);
    92. }
    93. if (res) {
    94. if (!signal)
    95. const_cast(sender)->disconnectNotify(QMetaMethod());
    96. }
    97. return res;
    98. }

    将对象发送者中的信号与对象接收者中的方法断开。 如果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);

    下面分析代码:

    1. if (signal) {
    2. QT_TRY {
    3. signal_name = QMetaObject::normalizedSignature(signal);
    4. signal = signal_name.constData();
    5. } QT_CATCH (const std::bad_alloc &) {
    6. // if the signal is already normalized, we can continue.
    7. if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
    8. QT_RETHROW;
    9. }
    10. if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
    11. return false;
    12. signal++; // skip code
    13. }

    如果参数 signal不为空,则获取signal的名称。

    1. QByteArray method_name;
    2. const char *method_arg = method;
    3. int membcode = -1;
    4. bool method_found = false;
    5. if (method) {
    6. QT_TRY {
    7. method_name = QMetaObject::normalizedSignature(method);
    8. method = method_name.constData();
    9. } QT_CATCH(const std::bad_alloc &) {
    10. // if the method is already normalized, we can continue.
    11. if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
    12. QT_RETHROW;
    13. }
    14. membcode = extract_code(method);
    15. if (!check_method_code(membcode, receiver, method, "disconnect"))
    16. return false;
    17. method++; // skip code
    18. }

    如果参数 method不为空,则获取method的名称。

    接下来,遍历查找sender和receiver的meta objects.

    1. do {
    2. int signal_index = -1;
    3. if (signal) {
    4. signal_index = QMetaObjectPrivate::indexOfSignalRelative(
    5. &smeta, signalName, signalTypes.size(), signalTypes.constData());
    6. if (signal_index < 0)
    7. break;
    8. signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
    9. signal_index += QMetaObjectPrivate::signalOffset(smeta);
    10. signal_found = true;
    11. }
    12. if (!method) {
    13. res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, 0);
    14. } else {
    15. const QMetaObject *rmeta = receiver->metaObject();
    16. do {
    17. int method_index = QMetaObjectPrivate::indexOfMethod(
    18. rmeta, methodName, methodTypes.size(), methodTypes.constData());
    19. if (method_index >= 0)
    20. while (method_index < rmeta->methodOffset())
    21. rmeta = rmeta->superClass();
    22. if (method_index < 0)
    23. break;
    24. res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, 0);
    25. method_found = true;
    26. } while ((rmeta = rmeta->superClass()));
    27. }
    28. } while (signal && (smeta = smeta->superClass()));

    调用QMetaObjectPrivate::disconnect

    1. bool QMetaObjectPrivate::disconnect(const QObject *sender,
    2. int signal_index, const QMetaObject *smeta,
    3. const QObject *receiver, int method_index, void **slot,
    4. DisconnectType disconnectType)
    5. {
    6. if (!sender)
    7. return false;
    8. QObject *s = const_cast(sender);
    9. QBasicMutex *senderMutex = signalSlotLock(sender);
    10. QBasicMutexLocker locker(senderMutex);
    11. QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
    12. if (!scd)
    13. return false;
    14. bool success = false;
    15. {
    16. // prevent incoming connections changing the connections->receivers while unlocked
    17. QObjectPrivate::ConnectionDataPointer connections(scd);
    18. if (signal_index < 0) {
    19. // remove from all connection lists
    20. for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
    21. if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
    22. success = true;
    23. }
    24. } else if (signal_index < scd->signalVectorCount()) {
    25. if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
    26. success = true;
    27. }
    28. }
    29. locker.unlock();
    30. if (success) {
    31. scd->cleanOrphanedConnections(s);
    32. QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
    33. if (smethod.isValid())
    34. s->disconnectNotify(smethod);
    35. }
    36. return success;
    37. }

       首先,获取ConnectionData *scd。

       之后,根据scd移除相应的connections.

       从函数QMetaObjectPrivate::disconnect返回, 返回值保存在res。

    如果signal 或者 method 没找到,则提示错误。

    1. if (signal && !signal_found) {
    2. err_method_notfound(sender, signal_arg, "disconnect");
    3. err_info_about_objects("disconnect", sender, receiver);
    4. } else if (method && !method_found) {
    5. err_method_notfound(receiver, method_arg, "disconnect");
    6. err_info_about_objects("disconnect", sender, receiver);
    7. }

    如果res的值为true,调用sender的disconnectNotify函数。

    2.dumpObjectInfo()

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

    1. void QObject::dumpObjectInfo()
    2. {
    3. const_cast<const QObject *>(this)->dumpObjectInfo();
    4. }

    1. void QObject::dumpObjectInfo() const
    2. {
    3. qDebug("OBJECT %s::%s", metaObject()->className(),
    4. objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
    5. Q_D(const QObject);
    6. QBasicMutexLocker locker(signalSlotLock(this));
    7. // first, look for connections where this object is the sender
    8. qDebug(" SIGNALS OUT");
    9. QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
    10. if (cd && cd->signalVectorCount()) {
    11. QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
    12. for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
    13. const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
    14. if (!c)
    15. continue;
    16. const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
    17. qDebug(" signal: %s", signal.methodSignature().constData());
    18. // receivers
    19. while (c) {
    20. if (!c->receiver.loadRelaxed()) {
    21. qDebug(" ");
    22. c = c->nextConnectionList.loadRelaxed();
    23. continue;
    24. }
    25. if (c->isSlotObject) {
    26. qDebug(" ");
    27. c = c->nextConnectionList.loadRelaxed();
    28. continue;
    29. }
    30. const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
    31. const QMetaMethod method = receiverMetaObject->method(c->method());
    32. qDebug(" --> %s::%s %s",
    33. receiverMetaObject->className(),
    34. c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
    35. method.methodSignature().constData());
    36. c = c->nextConnectionList.loadRelaxed();
    37. }
    38. }
    39. } else {
    40. qDebug( " " );
    41. }
    42. // now look for connections where this object is the receiver
    43. qDebug(" SIGNALS IN");
    44. if (cd && cd->senders) {
    45. for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
    46. QByteArray slotName = QByteArrayLiteral("");
    47. if (!s->isSlotObject) {
    48. const QMetaMethod slot = metaObject()->method(s->method());
    49. slotName = slot.methodSignature();
    50. }
    51. qDebug(" <-- %s::%s %s",
    52. s->sender->metaObject()->className(),
    53. s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
    54. slotName.constData());
    55. }
    56. } else {
    57. qDebug(" ");
    58. }
    59. }

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

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

    3.dumpObjectTree()

    将子树转储到调试输出。

    1. void QObject::dumpObjectTree()
    2. {
    3. const_cast<const QObject *>(this)->dumpObjectTree();
    4. }
    1. /*!
    2. Dumps a tree of children to the debug output.
    3. \note before Qt 5.9, this function was not const.
    4. \sa dumpObjectInfo()
    5. */
    6. void QObject::dumpObjectTree() const
    7. {
    8. dumpRecursive(0, this);
    9. }
    10. static void dumpRecursive(int level, const QObject *object)
    11. {
    12. if (object) {
    13. QByteArray buf;
    14. buf.fill(' ', level / 2 * 8);
    15. if (level % 2)
    16. buf += " ";
    17. QString name = object->objectName();
    18. QString flags = QLatin1String("");
    19. #if 0
    20. if (qApp->focusWidget() == object)
    21. flags += 'F';
    22. if (object->isWidgetType()) {
    23. QWidget * w = (QWidget *)object;
    24. if (w->isVisible()) {
    25. QString t("<%1,%2,%3,%4>");
    26. flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height());
    27. } else {
    28. flags += 'I';
    29. }
    30. }
    31. #endif
    32. qDebug("%s%s::%s %s", (const char*)buf, object->metaObject()->className(), name.toLocal8Bit().data(),
    33. flags.toLatin1().data());
    34. QObjectList children = object->children();
    35. if (!children.isEmpty()) {
    36. for (int i = 0; i < children.size(); ++i)
    37. dumpRecursive(level+1, children.at(i));
    38. }
    39. }
    40. }

    递归输出object的meta信息。

    缩进用了一个技巧:

    1. QByteArray buf;
    2. buf.fill(' ', level / 2 * 8);
    3. if (level % 2)
    4. buf += " ";

    根据level层级,计算缩进大小。

  • 相关阅读:
    【Android】系统源码下载及编译和android studio导入
    【高并发】从源码角度深度解析线程池是如何实现优雅退出的
    java基于springboot社区共享食堂订餐信息系统maven
    springboot+vue+elementui教师下乡支教岗位申请系统java项目源码
    1.5、计算机网络的性能指标(1)
    【Java项目】如何设计一个用户签到系统?并且这个签到系统支持7天,14天等不同天数的连续签到功能?
    2022 版史上最全 Java 八股文,没有任何异议
    【刷题笔记9.25】LeetCode:相交链表
    【Java八股文总结】之数据结构
    【排版教程】使用Latex ACM 双栏会议模板如何添加跨栏的图片
  • 原文地址:https://blog.csdn.net/exlink2012/article/details/125603203