QT QObject源码学习(二)

news/2024/9/18 15:01:42/ 标签: qt, c++
一、全局函数
qt_qFindChildren_helper_1">1、qt_qFindChildren_helper函数

在给定的父对象下,查找所有匹配指定条件的子对象,并将它们添加到一个列表中。
(1)声明

/*** @brief 在给定的父对象下,查找所有匹配指定条件的子对象,并将它们添加到一个列表中。* * @param parent  指向要查找子对象的父对象的指针。* @param name 要匹配的子对象名称。如果为 null,则不进行名称匹配。* @param mo QMetaObject 对象的引用,用于判断子对象的类型。* @param list 指向 QList<void*> 的指针,用于存储找到的子对象。* @param options 查找选项,指定是否需要递归查找子对象。* @return  */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);

(2)源码实现

void qt_qFindChildren_helper(const QObject *parent, const QString &name,const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
{if (!parent || !list)return;// 获取该 parent 对象的所有直接子对象const QObjectList &children = parent->children();QObject *obj;// 循环遍历所有子对象。for (int i = 0; i < children.size(); ++i) {obj = children.at(i);if (mo.cast(obj)) {if (name.isNull() || obj->objectName() == name)list->append(obj);}// 如果 options 包含 Qt::FindChildrenRecursively 标志,则递归调用 qt_qFindChildren_helper 函数,对当前子对象继续进行查找。if (options & Qt::FindChildrenRecursively)qt_qFindChildren_helper(obj, name, mo, list, options);}
}

(3)举例

void MainWindow::test_find_children_object_by_name()
{// 创建一个 QWidget 作为根对象QWidget root;// 创建子 QWidget 对象QWidget child1(&root);child1.setObjectName("targetObject");QWidget child2(&root);child2.setObjectName("anotherObject");// 创建一个子子对象QWidget grandChild(&child1);grandChild.setObjectName("targetObject");// 定义查找条件QString nameToFind("targetObject");const QMetaObject &metaObject = QWidget::staticMetaObject;QList<void*> foundList;// 查找所有满足条件的对象qt_qFindChildren_helper(&root, nameToFind, metaObject, &foundList, Qt::FindChildrenRecursively);// 打印找到的对象for (void *obj : foundList) {QWidget *widget = static_cast<QWidget*>(obj);qDebug() << "Found widget with objectName:" << widget->objectName();}
}
qt_qFindChildren_helper_78">2、qt_qFindChildren_helper函数

递归查找 QObject 类型的子对象,满足特定条件(如对象名称匹配正则表达式)的对象。
(1)声明

/*** @brief 递归查找 QObject 类型的子对象,满足特定条件(如对象名称匹配正则表达式)的对象* * @param parent 要查找的起始父对象。* @param re 用于匹配对象名称的正则表达式。* @param mo 目标对象的 QMetaObject,用于类型检查。* @param list 用于存储找到的对象指针的列表。* @param options  查找选项,如是否递归查找子对象。* @return */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegExp &re,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);

(2)源码实现

void qt_qFindChildren_helper(const QObject *parent, const QRegExp &re,const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
{if (!parent || !list)return;// 获取 parent 的所有直接子对象列表。const QObjectList &children = parent->children();// 创建 QRegExp 的副本 reCopy,用于后续的匹配操作。QRegExp reCopy = re;QObject *obj;// 遍历 parent 的所有子对象。for (int i = 0; i < children.size(); ++i) {obj = children.at(i);// 对于每个子对象,检查其是否是 mo 类型的对象,并且其 objectName 是否匹配 reCopy 正则表达式。如果匹配,则将该对象添加到 list 中。if (mo.cast(obj) && reCopy.indexIn(obj->objectName()) != -1)list->append(obj);            // 如果 options 包含 Qt::FindChildrenRecursively,则对每个子对象递归调用 qt_qFindChildren_helper 函数,以查找其子对象。if (options & Qt::FindChildrenRecursively)qt_qFindChildren_helper(obj, re, mo, list, options);}
}

(3)举例

void MainWindow::test_find_children_object_by_re()
{// 创建一个 QWidget 作为根对象QWidget root;// 创建子 QWidget 对象,设置 objectNameQWidget child1(&root);child1.setObjectName("button1");QWidget child2(&root);child2.setObjectName("button2");QWidget child3(&root);child3.setObjectName("textField");QWidget child4(&root);child4.setObjectName("button3");// 创建一个子子对象QWidget grandChild(&child1);grandChild.setObjectName("button1Child");// 设置正则表达式,用于匹配包含 "button" 的名称QRegExp re("button");// 查找条件const QMetaObject &metaObject = QWidget::staticMetaObject;QList<void*> foundList;// 查找所有匹配的对象qt_qFindChildren_helper(&root, re, metaObject, &foundList, Qt::FindChildrenRecursively);// 打印找到的对象名称for (void *obj : foundList) {QWidget *widget = static_cast<QWidget*>(obj);qDebug() << "Found widget with objectName:" << widget->objectName();}
}
qt_qFindChildren_helper_164">3、qt_qFindChildren_helper函数

递归地查找并返回匹配特定正则表达式的 QObject 类型的子对象。
(1)声明

/*** @brief 递归地查找并返回匹配特定正则表达式的 QObject 类型的子对象* * @param parent 查找的起始父对象。* @param re 用于匹配对象名称的正则表达式。* @param mo 目标对象的 QMetaObject,用于检查对象类型。* @param list 存储找到的对象指针的列表。* @param options 查找选项,例如是否递归查找子对象。* @return Q_CORE_EXPORT */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);

(2)源码实现

void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
{if (!parent || !list)return;// 获取 parent 的所有直接子对象。const QObjectList &children = parent->children();QObject *obj;for (int i = 0; i < children.size(); ++i) {obj = children.at(i);// 对每个子对象,检查其是否是指定类型 mo 的对象。if (mo.cast(obj)) {// 使用 QRegularExpression 对象名称进行匹配,如果匹配,则将该对象添加到 list 中。QRegularExpressionMatch m = re.match(obj->objectName());if (m.hasMatch())list->append(obj);}// 如果 options 包含 Qt::FindChildrenRecursively,对每个子对象递归调用 qt_qFindChildren_helper 函数。if (options & Qt::FindChildrenRecursively)qt_qFindChildren_helper(obj, re, mo, list, options);}
}

(3)举例

void MainWindow::test_find_children_object_by_regularExpression()
{// 创建一个 QWidget 作为根对象QWidget root;// 创建子 QWidget 对象,设置 objectNameQWidget child1(&root);child1.setObjectName("label1");QWidget child2(&root);child2.setObjectName("button");QWidget child3(&root);child3.setObjectName("label2");QWidget child4(&root);child4.setObjectName("textfield");// 创建一个子子对象QWidget grandChild(&child1);grandChild.setObjectName("label1Child");// 设置正则表达式,用于匹配包含 "label" 的名称QRegularExpression re("label");// 查找条件const QMetaObject &metaObject = QWidget::staticMetaObject;QList<void*> foundList;// 查找所有匹配的对象qt_qFindChildren_helper(&root, re, metaObject, &foundList, Qt::FindChildrenRecursively);// 打印找到的对象名称for (void *obj : foundList) {QWidget *widget = static_cast<QWidget*>(obj);qDebug() << "Found widget with objectName:" << widget->objectName();}
}
qt_qFindChild_helper_251">4、qt_qFindChild_helper函数

用于在 QObject 的子对象中查找匹配特定名称和类型的单个对象。
(1)声明

/*** @brief 用于在 QObject 的子对象中查找匹配特定名称和类型的单个对象。* * @param parent 查找的起始对象。* @param name 要匹配的对象名称。* @param mo 对象的元对象,用于验证对象的类型。* @param options 查找选项,例如是否递归查找。* @return 查找到的对象*/
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);

(2)源码实现

QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
{if (!parent)return 0;// 获取 parent 的所有直接子对象。const QObjectList &children = parent->children();QObject *obj;int i;// 遍历子对象for (i = 0; i < children.size(); ++i) {obj = children.at(i);// 检查每个对象是否匹配指定的类型和名称;如果找到匹配的对象,则立即返回。if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))return obj;}// 如果 options 包含 Qt::FindChildrenRecursively,则对每个子对象递归调用 qt_qFindChild_helper。if (options & Qt::FindChildrenRecursively) {for (i = 0; i < children.size(); ++i) {obj = qt_qFindChild_helper(children.at(i), name, mo, options);// 如果在子对象中找到了匹配的对象,则返回该对象。if (obj)return obj;}}return 0;
}

(3)举例

void MainWindow::test_find_child_object_by_name()
{// 创建一个 QWidget 作为根对象QWidget root;// 创建子 QWidget 对象,设置 objectNameQWidget child1(&root);child1.setObjectName("targetWidget");QWidget child2(&root);child2.setObjectName("otherWidget");QWidget child3(&root);child3.setObjectName("anotherWidget");QWidget grandChild(&child1);grandChild.setObjectName("childOfTarget");// 查找条件const QMetaObject &metaObject = QWidget::staticMetaObject;QString nameToFind = "targetWidget";// 查找对象QObject *foundObject = qt_qFindChild_helper(&root, nameToFind, metaObject, Qt::FindChildrenRecursively);if (foundObject) {qDebug() << "Found object with name:" << foundObject->objectName();} else {qDebug() << "Object not found.";}
}
5、qobject_cast函数
// 用于在 Qt 的对象模型中进行类型安全的转换。它们是 QObject 类及其派生类之间进行类型转换的工具。
// 模板类型参数 T: 这是一个模板参数,表示要转换的目标类型。
template <class T>
inline T qobject_cast(QObject *object)
{// std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType: 这行代码用于去掉 T 的常量(const)和指针(*)修饰符,得到 ObjType。这是因为 qobject_cast 通常用于去掉类型修饰符后进行实际的转换。typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;// Q_STATIC_ASSERT_X: 这个宏用于静态断言,确保 ObjType 类型确实具有 Q_OBJECT 宏。这个检查是必要的,因为 qobject_cast 依赖于 Qt 的元对象系统来进行类型转换。Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"qobject_cast requires the type to have a Q_OBJECT macro");// ObjType::staticMetaObject.cast(object): 这行代码调用了 ObjType 类的 staticMetaObject 的 cast 方法,该方法是 Qt 元对象系统提供的,用于执行实际的类型转换。cast 方法尝试将 object 转换为 ObjType 类型,如果成功,返回转换后的对象指针;如果失败,返回 nullptr。// static_cast<T>: 最后,使用 static_cast 将 cast 方法的结果转换为模板参数类型 T。return static_cast<T>(ObjType::staticMetaObject.cast(object));
}// const QObject *object: 这个版本接受一个 const QObject * 类型的参数,适用于不能修改的 QObject 指针。
template <class T>
inline T qobject_cast(const QObject *object)
{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"qobject_cast requires the type to have a Q_OBJECT macro");return static_cast<T>(ObjType::staticMetaObject.cast(object));
}

qobject_cast 是 Qt 提供的一种类型安全的类型转换工具,类似于 C++ 的 dynamic_cast,但专为 Qt 的元对象系统设计。它检查目标类型是否具有 Q_OBJECT 宏(这对于元对象系统是必须的),然后尝试进行类型转换。函数的两个版本分别支持可修改和只读的 QObject 指针类型。这种机制利用了 Qt 的元对象系统,通过类型的 staticMetaObject 来执行安全的运行时类型检查和转换。

6、qobject_interface_iid函数
// 这个模板函数 qobject_interface_iid 返回一个 const char * 类型的指针,指向 Q_NULLPTR(一个宏,通常定义为 nullptr)。它的目的是为接口提供一个默认的接口ID(Interface ID)。对于任何没有特化这个模板的类型,都会返回 Q_NULLPTR。
template <class T> inline const char * qobject_interface_iid()
{ return Q_NULLPTR; }// Q_MOC_RUN 是一个预处理器宏,用来防止 Qt 的元对象编译器(MOC)在处理时包含这段代码。MOC 处理 Qt 的元对象系统,如信号和槽机制,因此在 MOC 运行时,宏中的代码不会被展开。这样可以避免宏展开对 MOC 的干扰。
#ifndef Q_MOC_RUN
// Q_DECLARE_INTERFACE 是一个宏定义,用于声明一个 Qt 接口及其 ID。它通常用于插件的接口定义。
// IFace 是接口类型的名称,IId 是该接口的 ID。
#  define Q_DECLARE_INTERFACE(IFace, IId) \
// 这段代码特化了 qobject_interface_iid 模板函数,使其返回接口的 ID 字符串 IId,这样可以在运行时通过接口 ID 区分不同的接口。template <> inline const char *qobject_interface_iid<IFace *>() \{ return IId; } \
// 这两个特化版本的 qobject_cast 函数尝试将 QObject 对象转换为 IFace 接口类型。如果对象存在并且可以转换,则返回转换后的接口指针;否则返回 Q_NULLPTR。template <> inline IFace *qobject_cast<IFace *>(QObject *object) \{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : Q_NULLPTR)); } \template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \{ return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : Q_NULLPTR)); }
#endif // Q_MOC_RUN

这段代码帮助在 Qt 的插件系统中处理接口和类型转换,确保插件和应用程序能够通过接口 ID 正确识别和转换接口。

二、QObjectData类

QObjectData 是 QObject 的一个内部数据结构,用于存储和管理 QObject 的状态、父子关系、事件和元信息等。它包含了对 QObject 自身和其子对象的指针,以及用于标记对象状态的位字段。通过这些数据,Qt 能够高效地管理对象的生命周期、信号和槽机制,以及事件分发等功能。
1、声明如下:

class Q_CORE_EXPORT QObjectData {
public:// 这是一个纯虚析构函数,表示 QObjectData 是一个抽象基类,不能直接实例化。纯虚析构函数表明这个类是一个接口类,通常用于定义接口或基类的行为。virtual ~QObjectData() = 0;//  指向 QObject 的指针,通常指向 QObject 自身的 this 指针,用于管理对象的状态或访问对象QObject *q_ptr;// 指向 QObject 的父对象。QObject 对象通常有一个父对象,父对象负责管理其子对象的生命周期QObject *parent;// 存储子对象的列表。QObjectList 是一个 QObject 指针的容器,用于存储所有子对象QObjectList children;// 这些位字段是用于存储 QObject 的状态标志,以节省内存和提高访问效率// 标记对象是否是一个 QWidget(即窗口部件)uint isWidget : 1;// 标记是否阻塞了信号uint blockSig : 1;//  标记对象是否已被删除uint wasDeleted : 1;// 标记是否正在删除子对象uint isDeletingChildren : 1;// 标记是否发送子对象事件uint sendChildEvents : 1;// 标记是否接收子对象事件uint receiveChildEvents : 1;// 标记对象是否是窗口(QWindow)uint isWindow : 1; //for QWindow// 标记是否调用了 deleteLater() 方法uint deleteLaterCalled : 1;// 保留未使用的位字段uint unused : 24;//  存储已发布的事件数量int postedEvents;// 指向 QDynamicMetaObjectData 对象的指针,表示对象的动态元对象数据。动态元对象用于处理动态创建的信号和槽。QDynamicMetaObjectData *metaObject;// 这是一个成员函数,用于获取对象的动态元对象。QMetaObject 是描述 QObject 类和其元信息的类。QMetaObject *dynamicMetaObject() const;
};

2、用法
(1)创建和连接信号槽

    // 1、创建和连接信号槽TestQObjectData obj;QObject::connect(&obj, &TestQObjectData::mySignal, &obj, &TestQObjectData::mySlot);emit obj.mySignal();  // 会调用 mySlot()

(2)管理对象的父子关系

    // 2、管理对象的父子关系QWidget *parentWidget = new QWidget;QPushButton *button = new QPushButton(parentWidget);// button 的父对象是 parentWidget,点击按钮时,按钮会自动被删除

(3)使用 deleteLater() 安排对象删除

    QWidget *widget3 = new QWidget;widget3->deleteLater();  // 对象将在事件循环空闲时被删除

(4)使用 dynamicMetaObject()

    QWidget *widget = new QWidget;const QMetaObject *metaObject = widget->metaObject();qDebug() << "Class name:" << metaObject->className();
三、QDynamicMetaObjectData和QAbstractDynamicMetaObject

这两个结构体 QDynamicMetaObjectData 和 QAbstractDynamicMetaObject,它们在 Qt 框架中用于动态元对象系统。这两个结构体的目的是提供动态类型信息和方法调用机制。

struct QAbstractDynamicMetaObject;
// 提供了接口用于动态元对象的基本操作,包括动态方法调用和对象销毁。
struct Q_CORE_EXPORT QDynamicMetaObjectData
{// 定义了一个虚析构函数,允许通过基类指针删除派生类对象而不会发生未定义行为。virtual ~QDynamicMetaObjectData();// 是一个虚函数,默认实现为删除当前对象。这通常用于清理工作。virtual void objectDestroyed(QObject *) { delete this; }// 是一个纯虚函数,需要派生类实现。它返回一个 QAbstractDynamicMetaObject 指针,代表动态元对象。virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;// 是一个纯虚函数,需要派生类实现。它处理元对象的调用,metaCall 通常用于动态调用对象的方法。virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
};// QAbstractDynamicMetaObject 继承了 QDynamicMetaObjectData 和 QMetaObject。它不仅具备 QDynamicMetaObjectData 的动态元对象处理能力,还包含了 QMetaObject 的标准元对象功能。
// 是一个具体实现,提供了对动态元对象系统的支持,并且能够处理方法调用和属性创建等操作。它还重写了 QDynamicMetaObjectData 的方法来实现具体功能。
struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
{// 是析构函数。由于这个结构体继承自多个基类,析构函数负责正确清理资源。~QAbstractDynamicMetaObject();// 实现了 QDynamicMetaObjectData 中的 toDynamicMetaObject 函数,返回当前对象的指针,表示当前对象是一个 QAbstractDynamicMetaObject 类型的动态元对象。virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) Q_DECL_OVERRIDE { return this; }// 是一个实现了 QMetaObject 中的虚函数的默认实现,这个函数用于创建属性。默认实现返回 -1 表示创建失败。virtual int createProperty(const char *, const char *) { return -1; }// 重写了 QDynamicMetaObjectData 中的 metaCall 函数,调用 metaCall(QMetaObject::Call, int _id, void **) 进行处理。virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) Q_DECL_OVERRIDE{ return metaCall(c, _id, a); }// 这是一个兼容性重载版本的 metaCall,它简单地返回 _id,没有实际处理调用。这个实现通常用于提供向下兼容的接口。virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
};
三、QObject类
0、源码
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/#ifndef QOBJECT_H
#define QOBJECT_H#ifndef QT_NO_QOBJECT#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
#ifdef QT_INCLUDE_COMPAT
#include <QtCore/qcoreevent.h>
#endif
#include <QtCore/qscopedpointer.h>
#include <QtCore/qmetatype.h>#include <QtCore/qobject_impl.h>#if QT_HAS_INCLUDE(<chrono>)
#  include <chrono>
#endifQT_BEGIN_NAMESPACEclass QEvent;
class QTimerEvent;
class QChildEvent;
struct QMetaObject;
class QVariant;
class QObjectPrivate;
class QObject;
class QThread;
class QWidget;
#ifndef QT_NO_REGEXP
class QRegExp;
#endif
#ifndef QT_NO_REGULAREXPRESSION
class QRegularExpression;
#endif
#ifndef QT_NO_USERDATA
class QObjectUserData;
#endif
struct QDynamicMetaObjectData;typedef QList<QObject*> QObjectList;/*** @brief 在给定的父对象下,查找所有匹配指定条件的子对象,并将它们添加到一个列表中。* * @param parent  指向要查找子对象的父对象的指针。* @param name 要匹配的子对象名称。如果为 null,则不进行名称匹配。* @param mo QMetaObject 对象的引用,用于判断子对象的类型。* @param list 指向 QList<void*> 的指针,用于存储找到的子对象。* @param options 查找选项,指定是否需要递归查找子对象。* @return  */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);/*** @brief 递归查找 QObject 类型的子对象,满足特定条件(如对象名称匹配正则表达式)的对象* * @param parent 要查找的起始父对象。* @param re 用于匹配对象名称的正则表达式。* @param mo 目标对象的 QMetaObject,用于类型检查。* @param list 用于存储找到的对象指针的列表。* @param options  查找选项,如是否递归查找子对象。* @return */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegExp &re,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);/*** @brief 递归地查找并返回匹配特定正则表达式的 QObject 类型的子对象* * @param parent 查找的起始父对象。* @param re 用于匹配对象名称的正则表达式。* @param mo 目标对象的 QMetaObject,用于检查对象类型。* @param list 存储找到的对象指针的列表。* @param options 查找选项,例如是否递归查找子对象。* @return Q_CORE_EXPORT */
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);/*** @brief 用于在 QObject 的子对象中查找匹配特定名称和类型的单个对象。* * @param parent 查找的起始对象。* @param name 要匹配的对象名称。* @param mo 对象的元对象,用于验证对象的类型。* @param options 查找选项,例如是否递归查找。* @return 查找到的对象*/
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);/*** @brief QObjectData 是 QObject 的一个内部数据结构,用于存储和管理 QObject 的状态、父子关系、事件和元信息等。它包含了对 QObject 自身和其子对象的指针,以及用于标记对象状态的位字段。通过这些数据,Qt 能够高效地管理对象的生命周期、信号和槽机制,以及事件分发等功能。* */
class Q_CORE_EXPORT QObjectData {
public:// 这是一个纯虚析构函数,表示 QObjectData 是一个抽象基类,不能直接实例化。纯虚析构函数表明这个类是一个接口类,通常用于定义接口或基类的行为。virtual ~QObjectData() = 0;//  指向 QObject 的指针,通常指向 QObject 自身的 this 指针,用于管理对象的状态或访问对象QObject *q_ptr;// 指向 QObject 的父对象。QObject 对象通常有一个父对象,父对象负责管理其子对象的生命周期QObject *parent;// 存储子对象的列表。QObjectList 是一个 QObject 指针的容器,用于存储所有子对象QObjectList children;// 这些位字段是用于存储 QObject 的状态标志,以节省内存和提高访问效率// 标记对象是否是一个 QWidget(即窗口部件)uint isWidget : 1;// 标记是否阻塞了信号uint blockSig : 1;//  标记对象是否已被删除uint wasDeleted : 1;// 标记是否正在删除子对象uint isDeletingChildren : 1;// 标记是否发送子对象事件uint sendChildEvents : 1;// 标记是否接收子对象事件uint receiveChildEvents : 1;// 标记对象是否是窗口(QWindow)uint isWindow : 1; //for QWindow// 标记是否调用了 deleteLater() 方法uint deleteLaterCalled : 1;// 保留未使用的位字段uint unused : 24;//  存储已发布的事件数量int postedEvents;// 指向 QDynamicMetaObjectData 对象的指针,表示对象的动态元对象数据。动态元对象用于处理动态创建的信号和槽。QDynamicMetaObjectData *metaObject;// 这是一个成员函数,用于获取对象的动态元对象。QMetaObject 是描述 QObject 类和其元信息的类。QMetaObject *dynamicMetaObject() const;
};class Q_CORE_EXPORT QObject
{// Q_OBJECT: 这个宏启用 Qt 的元对象系统,为 QObject 提供信号和槽机制,以及其他 Qt 特性。它会引导 Qt 的元对象编译器(MOC)生成额外的代码,处理信号和槽的连接等。Q_OBJECT// Q_PROPERTY: 这个宏声明了一个属性 objectName。它使得该属性可以通过 Qt 的元对象系统进行读取、写入和通知。// QString objectName: 属性的类型是 QString。// READ objectName: 指定属性的读取函数是 objectName()。// WRITE setObjectName: 指定属性的写入函数是 setObjectName()。// NOTIFY objectNameChanged: 指定当属性值改变时发射的信号是 objectNameChanged。Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)// Q_DECLARE_PRIVATE: 这个宏用于声明 QObject 类的私有实现类的访问权限。它与 Q_D 宏一起使用,允许类的公共接口访问其私有实现。这有助于实现封装和分离接口与实现的细节。Q_DECLARE_PRIVATE(QObject)public:// Q_INVOKABLE:这是一个宏,标记该构造函数可以被 Qt 的元对象系统(例如通过信号和槽机制)调用。// explicit:这是一个 C++ 关键字,表示构造函数不能被隐式转换,仅能通过显式调用来创建对象。Q_INVOKABLE explicit QObject(QObject *parent=Q_NULLPTR);// 这是 QObject 类的虚析构函数。它确保在删除派生类对象时,会正确调用派生类的析构函数。virtual ~QObject();// 这是一个虚函数,用于处理事件。QEvent 是事件的基类,event 是传递给该函数的事件对象。该函数可以被重写以实现自定义事件处理逻辑。virtual bool event(QEvent *event);// 这是一个虚函数,用于事件过滤。它可以用来过滤或拦截某些事件,watched 是被监视的对象,event 是事件对象。这个函数允许你在事件到达目标对象之前,对其进行处理或过滤。virtual bool eventFilter(QObject *watched, QEvent *event);// 这是一个条件编译指令,用于在生成 Qt 文档时包含特定的代码。这通常用于文档生成工具(如 Doxygen)或其他文档相关的用途。
#ifdef Q_QDOC// 定义了一个静态方法,用于翻译 sourceText 字符串。comment 和 n 用于提供额外的上下文和信息。这个方法帮助处理国际化(i18n)问题,将字符串翻译成不同语言。static QString tr(const char *sourceText, const char *comment = Q_NULLPTR, int n = -1);// 与 tr 类似,但用于处理 UTF-8 编码的源文本。通常用于支持多字节字符编码的翻译。static QString trUtf8(const char *sourceText, const char *comment = Q_NULLPTR, int n = -1);// 虚方法,用于获取对象的 QMetaObject,这是 Qt 的元对象系统的一部分。它提供了有关对象类型和其成员的信息。virtual const QMetaObject *metaObject() const;// 静态成员变量,表示类的元对象。它用于在运行时提供关于类的类型信息。static const QMetaObject staticMetaObject;
#endif
// 条件编译指令,用于检查是否禁用了 Qt 的翻译功能。如果定义了 QT_NO_TRANSLATION,则编译器将包含下面的代码。
#ifdef QT_NO_TRANSLATION// 如果翻译功能被禁用,tr 方法将直接返回源文本转换为 UTF-8 编码的 QString。它不做任何翻译处理,只是简单地返回输入文本。static QString tr(const char *sourceText, const char * = Q_NULLPTR, int = -1){ return QString::fromUtf8(sourceText); }// 条件编译指令,用于检查 Qt 版本是否大于等于 5.0。如果是,则包含下面的代码。
#if QT_DEPRECATED_SINCE(5, 0)// 标记为已弃用(deprecated)的 trUtf8 方法。在翻译功能被禁用时,这个方法也将直接返回 UTF-8 编码的 QString。QT_DEPRECATED 说明此方法在未来版本中可能被移除或不推荐使用。QT_DEPRECATED static QString trUtf8(const char *sourceText, const char * = Q_NULLPTR, int = -1){ return QString::fromUtf8(sourceText); }
#endif
#endif //QT_NO_TRANSLATION// 获取对象的名称。QString objectName() const;// 设置对象的名称。void setObjectName(const QString &name);// 检查对象是否是一个 widget 类型。d_ptr 是一个指向实现细节的指针,isWidget 是一个成员变量。inline bool isWidgetType() const { return d_ptr->isWidget; }// 检查对象是否是一个窗口类型。inline bool isWindowType() const { return d_ptr->isWindow; }// 检查当前信号是否被阻塞。Q_DECL_NOTHROW 表示这个函数不会抛出异常。inline bool signalsBlocked() const Q_DECL_NOTHROW { return d_ptr->blockSig; }// 阻塞或解除阻塞信号。Q_DECL_NOTHROW 表示这个函数不会抛出异常。bool blockSignals(bool b) Q_DECL_NOTHROW;// 获取对象所在的线程。QThread *thread() const;// 将对象移动到指定的线程中。void moveToThread(QThread *thread);// 启动一个定时器,以指定的时间间隔和定时器类型。Qt::CoarseTimer 是默认的定时器类型。int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);//  检查是否包含 <chrono> 头文件或文档生成标志。
#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)Q_ALWAYS_INLINE// 重载的 startTimer 方法,接受 std::chrono::milliseconds 作为时间参数,并调用前面定义的 startTimer 方法。int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer){return startTimer(int(time.count()), timerType);}
#endif// 停止一个已启动的定时器,使用定时器 ID 来指定要停止的定时器。void killTimer(int id);// 模板函数用于根据名称和选项在对象树中查找指定类型的子对象,并返回该子对象的指针。   template<typename T>// aName 是用于匹配子对象名称的字符串,options 指定查找选项(默认递归查找)。函数返回类型为 T。inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const{// 定义 ObjType 类型别名,去除 T 的指针和常量修饰符,得到基础类型。这用于确保 qt_qFindChild_helper 函数获得正确的对象类型。typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;// 调用 qt_qFindChild_helper 函数查找子对象,并将结果转换为类型 T。this 是当前对象,aName 是子对象的名称,ObjType::staticMetaObject 是对象的元对象,options 是查找选项。return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));}// 该函数通过 qt_qFindChildren_helper 查找并返回当前对象中符合指定名称和选项的所有子对象,结果以 QList<T> 形式返回。这允许在 Qt 对象树中找到指定类型的所有子对象,并将它们收集到一个列表中。template<typename T>inline QList<T> findChildren(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const{// 定义一个类型别名 ObjType。通过 std::remove_pointer 去除 T 的指针部分,再通过 std::remove_cv 去除 T 的常量和易变性修饰符。ObjType 是 T 的基础类型(即 T 类型去除指针和修饰符后的类型)。这个别名用于与 qt_qFindChildren_helper 函数进行类型匹配。typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;QList<T> list;// 查找所有子对象qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,reinterpret_cast<QList<void *> *>(&list), options);return list;}#ifndef QT_NO_REGEXP// 函数通过正则表达式 re 查找当前对象中所有符合条件的子对象,并将它们以 QList<T> 的形式返回。template<typename T>inline QList<T> findChildren(const QRegExp &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;QList<T> list;qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,reinterpret_cast<QList<void *> *>(&list), options);return list;}
#endif#ifndef QT_NO_REGULAREXPRESSION// 模板函数 findChildren 使用了正则表达式来查找当前对象的所有符合条件的子对象,并将它们作为 QList<T> 返回。template<typename T>inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;QList<T> list;qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,reinterpret_cast<QList<void *> *>(&list), options);return list;}
#endif// 这是一个内联函数,返回当前对象的所有子对象的列表。QObjectList 是一个存储 QObject* 的容器。// d_ptr->children:这是一个指向实现细节的指针 d_ptr,通常用于 pimpl(Pointer to Implementation)模式,这里 children 是存储子对象的容器。inline const QObjectList &children() const { return d_ptr->children; }// 设置当前对象的父对象。将 parent 指针赋给当前对象的 parent 属性。修改对象的层级关系,改变对象的父子关系。void setParent(QObject *parent);// 安装事件过滤器,允许 filterObj 对象拦截和处理当前对象的事件。在事件分发过程中,filterObj 可以对事件进行处理或修改,从而影响事件的进一步处理。void installEventFilter(QObject *filterObj);// 移除事件过滤器,停止 obj 对象拦截当前对象的事件。取消对事件的处理,使得 obj 不再对当前对象的事件进行干预。void removeEventFilter(QObject *obj);/*** @brief 静态成员函数,用于连接 sender 对象的信号 signal 和 receiver 对象的槽 member。* * @param sender 信号发出的对象。* @param signal 信号的名称,格式为 SIGNAL(signalName(...))。* @param receiver 接收信号并处理的对象。* @param member 槽的名称,格式为 SLOT(slotName(...))。* @param type(默认使用 Qt::AutoConnection,自动选择合适的连接方式)。* @return QMetaObject::Connection QMetaObject::Connection,用于表示连接的句柄,可以用于断开连接。*/static QMetaObject::Connection connect(const QObject *sender, const char *signal,const QObject *receiver, const char *member, Qt::ConnectionType type = Qt::AutoConnection);/*** @brief 用于连接 sender 对象的信号(使用 QMetaMethod 对象表示)和 receiver 对象的槽(也使用 QMetaMethod 对象表示)。* * @param sender 信号发出的对象。* @param signal 信号的方法描述,使用 QMetaMethod 表示。* @param receiver 接收信号并处理的对象。* @param method 槽的方法描述,使用 QMetaMethod 表示。* @param type 连接类型(默认为 Qt::AutoConnection)。* @return QMetaObject::Connection 用于表示连接的句柄。*/static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,const QObject *receiver, const QMetaMethod &method,Qt::ConnectionType type = Qt::AutoConnection);/*** @brief 类的成员函数,用于连接 sender 对象的信号 signal 和当前对象的槽 member。* * @param sender 信号发出的对象。* @param signal 信号的名称,格式为 SIGNAL(signalName(...))。* @param member 槽的名称,格式为 SLOT(slotName(...))。* @param type 连接类型(默认为 Qt::AutoConnection)。* @return QMetaObject::Connection 用于表示连接的句柄。*/inline QMetaObject::Connection connect(const QObject *sender, const char *signal,const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;#ifdef Q_QDOC/*** @brief 连接 sender 对象的信号 signal 到 receiver 对象的槽 method* * @tparam PointerToMemberFunction * @param sender 信号发出的对象。* @param signal 信号的指针,表示为成员函数指针。* @param receiver 接收信号的对象。* @param method 槽的指针,表示为成员函数指针。* @param type 连接类型(默认为 Qt::AutoConnection)。* @return QMetaObject::Connection 用于表示连接的句柄*/template<typename PointerToMemberFunction>static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);/*** @brief 连接 sender 对象的信号 signal 到一个可调用对象(functor)。* * @tparam PointerToMemberFunction * @tparam Functor * @param sender 信号发出的对象。* @param signal 信号的指针,表示为成员函数指针。* @param functor 一个可调用对象,可以是函数对象、lambda 表达式等。* @return QMetaObject::Connection 用于表示连接的句柄*/template<typename PointerToMemberFunction, typename Functor>static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);/*** @brief 连接 sender 对象的信号 signal 到指定的上下文对象 context 的可调用对象 functor。* * @tparam PointerToMemberFunction * @tparam Functor * @param sender 信号发出的对象。* @param signal 信号的指针,表示为成员函数指针。* @param context 上下文对象,用于处理 functor 的执行。* @param functor 一个可调用对象,可以是函数对象、lambda 表达式等。* @param type 连接类型(默认为 Qt::AutoConnection)。* @return QMetaObject::Connection 用于表示连接的句柄。*/template<typename PointerToMemberFunction, typename Functor>static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
#else//Connect a signal to a pointer to qobject member function/*** @brief connect 函数模板用于将信号和槽连接起来,同时进行了一些编译时检查以确保类型安全。* * @tparam Func1 信号的函数类型。* @tparam Func2 槽的函数类型。* @param sender 发出信号的对象。* @param signal 信号的指针。* @param receiver 接收信号的对象。* @param slot 槽的指针。* @param type 连接类型,默认为 Qt::AutoConnection。* @return QMetaObject::Connection */template <typename Func1, typename Func2>static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<Func2> SlotType;Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),"The slot requires more arguments than the signal provides.");Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");const int *types = Q_NULLPTR;// 如果连接类型是 Qt::QueuedConnection 或 Qt::BlockingQueuedConnection,获取连接类型的参数。if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();// reinterpret_cast<void **>(&signal) 和 reinterpret_cast<void **>(&slot) 用于将函数指针转换为 void**。// QtPrivate::QSlotObject 创建一个槽对象。return connectImpl(sender, reinterpret_cast<void **>(&signal),receiver, reinterpret_cast<void **>(&slot),new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,typename SignalType::ReturnType>(slot),type, types, &SignalType::Object::staticMetaObject);}//connect to a function pointer  (not a member)/*** @brief connect 函数模板是一个重载版本,它用于连接信号和槽,提供了一个默认的连接类型 (Qt::DirectConnection)。* * @tparam Func1 信号的函数类型。* @tparam Func2 槽的函数类型。* @param sender 信号的发送者对象,类型为 const typename QtPrivate::FunctionPointer<Func1>::Object*。* @param signal 信号的函数指针。* @param slot 槽的函数指针。*/// std::enable_if 用于条件编译。只有当 QtPrivate::FunctionPointer<Func2>::ArgumentCount 大于或等于 0 时,函数模板才有效。// QtPrivate::FunctionPointer<Func2>::ArgumentCount 是 Func2 的参数数量的常量值。template <typename Func1, typename Func2>static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot){// 函数内部调用了另一个 connect 函数模板,传入 Qt::DirectConnection 作为连接类型。// 表示信号和槽都在同一个对象上连接,并且连接类型是 Qt::DirectConnection,即信号和槽在同一个线程中直接调用。return connect(sender, signal, sender, slot, Qt::DirectConnection);}//connect to a function pointer  (not a member)/*** @brief 这个模板函数用于连接信号和非成员槽函数(即 Func2 不是成员函数指针的情况下),并提供了默认的连接类型。它确保了信号和槽的参数及返回类型匹配,并支持队列连接类型。* * @tparam Func1 * @tparam Func2 * @param sender 发出信号的对象。* @param signal 信号的指针。* @param context 上下文对象(通常是槽所在的对象)* @param slot 槽函数指针。* @param type 连接类型,默认为 Qt::AutoConnection。* @return QMetaObject::Connection */template <typename Func1, typename Func2>static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&!QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<Func2> SlotType;// Q_STATIC_ASSERT_X 用于确保信号所在的类包含 Q_OBJECT 宏,信号的参数数量不少于槽的参数数量,信号和槽的参数兼容,并且信号和槽的返回类型兼容。Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),"The slot requires more arguments than the signal provides.");Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");const int *types = Q_NULLPTR;// 如果连接类型是 Qt::QueuedConnection 或 Qt::BlockingQueuedConnection,则获取连接类型的数组。if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();// 调用内部的 connectImpl 函数,传递信号和槽的指针,以及其他参数。return connectImpl(sender, reinterpret_cast<void **>(&signal), context, Q_NULLPTR,new QtPrivate::QStaticSlotObject<Func2,typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,typename SignalType::ReturnType>(slot),type, types, &SignalType::Object::staticMetaObject);}//connect to a functor// connect 函数模板用于在 Qt 框架中连接信号和槽。它利用 SFINAE 技术来确定是否启用该函数模板实例。函数的作用是根据信号和槽的类型来调用实际的连接函数,实现信号和槽的连接。Qt::DirectConnection 指定了连接的类型,确保信号和槽是直接连接的。template <typename Func1, typename Func2>// std::enable_if 是 C++ 标准库中的一个工具,用于根据条件启用或禁用模板特化。在这里,它用于启用这个 connect 函数的特定实例。// QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1这是一个模板类型 trait,判断槽函数 Func2 的参数数量是否为 -1。QtPrivate::FunctionPointer 是一个 Qt 内部使用的工具,用于提取函数指针的类型信息。// ArgumentCount 是一个静态常量,表示函数参数的数量。如果为 -1,表示函数没有参数,或者不确定参数数量。// typename std::enable_if<condition, QMetaObject::Connection>::type:如果条件 QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 成立,enable_if 类型会被定义为 QMetaObject::Connection。否则,这个 connect 函数模板实例不会被启用。static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot){return connect(sender, signal, sender, slot, Qt::DirectConnection);}//connect to a functor, with a "context" object defining in which event loop is going to be executedtemplate <typename Func1, typename Func2>static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection){typedef QtPrivate::FunctionPointer<Func1> SignalType;const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;Q_STATIC_ASSERT_X((FunctorArgumentCount >= 0),"Signal and slot arguments are not compatible.");const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");const int *types = Q_NULLPTR;if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();return connectImpl(sender, reinterpret_cast<void **>(&signal), context, Q_NULLPTR,new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,typename SignalType::ReturnType>(slot),type, types, &SignalType::Object::staticMetaObject);}
#endif //Q_QDOCstatic bool disconnect(const QObject *sender, const char *signal,const QObject *receiver, const char *member);static bool disconnect(const QObject *sender, const QMetaMethod &signal,const QObject *receiver, const QMetaMethod &member);inline bool disconnect(const char *signal = Q_NULLPTR,const QObject *receiver = Q_NULLPTR, const char *member = Q_NULLPTR) const{ return disconnect(this, signal, receiver, member); }inline bool disconnect(const QObject *receiver, const char *member = Q_NULLPTR) const{ return disconnect(this, Q_NULLPTR, receiver, member); }static bool disconnect(const QMetaObject::Connection &);#ifdef Q_QDOCtemplate<typename PointerToMemberFunction>static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method);
#elsetemplate <typename Func1, typename Func2>static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<Func2> SlotType;Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, reinterpret_cast<void **>(&slot),&SignalType::Object::staticMetaObject);}template <typename Func1>static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const QObject *receiver, void **zero){// This is the overload for when one wish to disconnect a signal from any slot. (slot=Q_NULLPTR)// Since the function template parameter cannot be deduced from '0', we use a// dummy void ** parameter that must be equal to 0Q_ASSERT(!zero);typedef QtPrivate::FunctionPointer<Func1> SignalType;return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, zero,&SignalType::Object::staticMetaObject);}
#endif //Q_QDOC#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)void dumpObjectTree(); // ### Qt 6: removevoid dumpObjectInfo(); // ### Qt 6: remove
#endif// 输出当前对象及其子对象的层次结构。它会递归地遍历对象树,显示对象之间的父子关系和结构。void dumpObjectTree() const;// 输出当前对象的详细信息。通常,它会显示对象的类型、名称以及其他有用的属性或状态信息。void dumpObjectInfo() const;#ifndef QT_NO_PROPERTIES// 设置对象的属性bool setProperty(const char *name, const QVariant &value);// 用于获取对象的属性QVariant property(const char *name) const;// 用于获取对象的所有动态属性名称。QList<QByteArray> dynamicPropertyNames() const;
#endif // QT_NO_PROPERTIES#ifndef QT_NO_USERDATA/*** @brief 注册一个新的用户数据 ID。这个函数通常用于生成一个唯一的 ID,用于后续存储和检索用户数据。* * @return uint 返回一个 uint 类型的唯一 ID,这个 ID 可以用于在对象上存储自定义的数据。*/static uint registerUserData();/*** @brief 为对象设置指定 ID 的用户数据。id 是先前通过 registerUserData() 获取的唯一 ID,data 是要存储的用户数据。* * @param id 用户数据的唯一标识符。* @param data 指向要存储的数据的指针。*/void setUserData(uint id, QObjectUserData* data);/*** @brief 获取与指定 ID 相关联的用户数据。id 是之前用于设置数据的唯一 ID。* * @param id 用于检索之前存储的用户数据,以便在对象的生命周期中访问和使用。* @return QObjectUserData* 返回一个 QObjectUserData* 指针,指向存储的数据。如果指定 ID 没有对应的数据,则返回 nullptr。*/QObjectUserData* userData(uint id) const;
#endif // QT_NO_USERDATAQ_SIGNALS:/*** @brief 这个信号在对象被销毁时发出。它通常用于在对象销毁前执行清理工作或更新相关的状态。* QObject * 是一个可选参数,指向被销毁的对象。如果信号发出时没有传递具体的参数,则默认为 Q_NULLPTR。*/void destroyed(QObject * = Q_NULLPTR);/*** @brief 这个信号在对象的名称(objectName)发生变化时发出。QPrivateSignal 是一个特殊的标记,用于表示这是一个私有信号,通常不会直接在外部连接到槽函数。* * @param objectName 新的对象名称。*/void objectNameChanged(const QString &objectName, QPrivateSignal);public:/*** @brief 返回当前对象的父对象。父对象用于管理对象的生命周期,确保在父对象销毁时,它的子对象也会被销毁。* * @return QObject* */inline QObject *parent() const { return d_ptr->parent; }/*** @brief 检查当前对象是否继承自指定的类。qt_metacast 是 Qt 的内部机制,用于类型转换。inherits 方法利用它来判断对象是否属于指定的类。* * @param classname 类名称* @return true * @return false */inline bool inherits(const char *classname) const{ return const_cast<QObject *>(this)->qt_metacast(classname) != Q_NULLPTR; }public Q_SLOTS:// deleteLater() 是 Qt 框架中的一个槽函数,允许你在当前事件处理完之后安全地删除对象。调用 deleteLater() 会将对象的删除请求放入事件队列中,确保在事件循环处理完当前事件后才执行真正的删除操作。这避免了在对象的生命周期内出现潜在的资源访问冲突或悬挂指针问题。这个方法特别适用于异步编程或在事件处理过程中需要删除对象的场景。void deleteLater();protected:// 返回发出信号的对象的指针。在槽函数中可以用来确定哪个对象触发了信号。QObject *sender() const;// 返回发出信号的信号索引。这个索引可以用来识别信号。通常用于调试和信号/槽机制的内部实现。int senderSignalIndex() const;// 返回连接到特定信号的槽函数数量。通过这个方法,你可以检查有多少个槽连接到某个信号int receivers(const char* signal) const;// 检查给定信号是否有槽函数连接。如果信号与槽连接,则返回 true。bool isSignalConnected(const QMetaMethod &signal) const;// 虚函数,处理计时器事件。子类可以重写这个函数来处理计时器触发的事件。virtual void timerEvent(QTimerEvent *event);// 虚函数,处理子对象的添加和移除事件。子类可以重写此函数以响应子对象的变化。virtual void childEvent(QChildEvent *event);// 虚函数,处理自定义事件。子类可以重写此函数以处理特定类型的自定义事件。virtual void customEvent(QEvent *event);// 虚函数,通知当信号被连接时。子类可以重写此函数以响应信号连接事件。virtual void connectNotify(const QMetaMethod &signal);// 虚函数,通知当信号断开连接时。子类可以重写此函数以响应信号断开事件。virtual void disconnectNotify(const QMetaMethod &signal);protected:/*** @brief QObject 类的保护构造函数,用于在子类中创建 QObject 实例时使用。* * @param dd 这是一个 QObjectPrivate 对象的引用,用于内部实现的私有数据。QObjectPrivate 是 QObject 类的内部机制的一部分,不应直接使用。* @param parent 这是一个指向父 QObject 的指针,用于设置对象的父对象。Q_NULLPTR 表示默认的无父对象。*/QObject(QObjectPrivate &dd, QObject *parent = Q_NULLPTR);protected:// d_ptr 是一个智能指针,管理 QObjectData 对象的生命周期。QObjectData 是用于存储 QObject 实例私有数据的类。QScopedPointer 确保 QObjectData 对象在 QObject 生命周期内正确地创建和销毁,防止内存泄漏。QScopedPointer<QObjectData> d_ptr;// staticQtMetaObject 是一个静态常量,保存了 QObject 类的元对象信息。QMetaObject 提供了关于类的运行时信息,例如信号和槽的定义。static const QMetaObject staticQtMetaObject;// 声明了一个友元函数 qt_getQtMetaObject,这个函数可以访问 QObject 类中的私有成员。Q_DECL_NOEXCEPT 表示该函数不会抛出异常。friend inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT;// QMetaObject 结构体被声明为 QObject 的友元,使其可以访问 QObject 的私有成员。QMetaObject 提供了 Qt 的元对象系统的功能。friend struct QMetaObject;// QMetaObjectPrivate 是 QMetaObject 的私有实现部分。通过将其声明为友元,QMetaObjectPrivate 可以访问 QObject 的私有数据和方法。friend struct QMetaObjectPrivate;// QMetaCallEvent 是 Qt 内部用于处理元对象调用事件的类。将其声明为友元允许它访问 QObject 的私有成员,以便处理信号和槽的调用。friend class QMetaCallEvent;// QApplication 是 Qt 应用程序的主类。作为友元,QApplication 可以访问 QObject 的内部实现细节,特别是在应用程序级别的操作和管理中。friend class QApplication;// QApplicationPrivate 是 QApplication 的私有实现部分。通过友元关系,它可以访问 QObject 的私有成员。friend class QApplicationPrivate;// QCoreApplication 是 QApplication 的基类,提供了核心应用程序功能。作为友元,QCoreApplication 可以访问 QObject 的内部实现细节。friend class QCoreApplication;// QCoreApplicationPrivate 是 QCoreApplication 的私有实现部分。友元关系允许它访问 QObject 的私有成员。friend class QCoreApplicationPrivate;// QWidget 是 Qt 的基本窗口部件类。作为友元,它可以访问 QObject 的私有实现,尤其是在界面组件的实现中。friend class QWidget;// 处理与线程相关的 QObject 数据。作为友元,它可以访问 QObject 的私有成员,用于线程相关的操作。friend class QThreadData;private://  禁止 QObject 类的拷贝构造函数和拷贝赋值操作符,它确保 QObject 对象不能被拷贝,只能通过移动或其他方式进行管理。这是因为 QObject 的复制可能会导致信号槽机制、事件处理等问题。Q_DISABLE_COPY(QObject)// 用于声明一个私有槽函数 _q_reregisterTimers,它在 QObject 的私有实现中定义。d_func() 是一个宏,用于获取 QObject 的私有数据。这个槽函数用于重新注册计时器,通常用于内部的定时器管理。Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))private:/*** @brief 用于建立信号和槽之间的连接。* * @param sender 发射信号的对象。* @param signal 指向发射信号的函数指针的指针。* @param receiver 接收信号的对象。* @param slotPtr 指向接收槽函数的指针的指针。* @param slot 封装槽函数的对象(QtPrivate::QSlotObjectBase 的实例)。* @param type 连接类型,指示是直接连接、队列连接还是其他类型。* @param types 信号和槽参数的类型数组。* @param senderMetaObject 发射信号的对象的元对象。* @return QMetaObject::Connection 是一个表示连接的对象,能够用于断开连接。*/static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,const QObject *receiver, void **slotPtr,QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,const int *types, const QMetaObject *senderMetaObject);/*** @brief 用于断开信号和槽之间的连接。* * @param sender 发射信号的对象。* @param signal 指向发射信号的函数指针的指针。* @param receiver 接收信号的对象。* @param slot 指向接收槽函数的指针的指针。* @param senderMetaObject 发射信号的对象的元对象。* @return true 返回值 bool 表示是否成功断开连接。* @return false */static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,const QMetaObject *senderMetaObject);};inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,const char *amember, Qt::ConnectionType atype) const
{ return connect(asender, asignal, this, amember, atype); }inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT
{ return &QObject::staticQtMetaObject; }#ifndef QT_NO_USERDATA
class Q_CORE_EXPORT QObjectUserData {
public:virtual ~QObjectUserData();
};
#endif#ifdef Q_QDOC
T qFindChild(const QObject *o, const QString &name = QString());
QList<T> qFindChildren(const QObject *oobj, const QString &name = QString());
QList<T> qFindChildren(const QObject *o, const QRegExp &re);
#endif
#if QT_DEPRECATED_SINCE(5, 0)
template<typename T>
inline QT_DEPRECATED T qFindChild(const QObject *o, const QString &name = QString())
{ return o->findChild<T>(name); }template<typename T>
inline QT_DEPRECATED QList<T> qFindChildren(const QObject *o, const QString &name = QString())
{return o->findChildren<T>(name);
}#ifndef QT_NO_REGEXP
template<typename T>
inline QT_DEPRECATED QList<T> qFindChildren(const QObject *o, const QRegExp &re)
{return o->findChildren<T>(re);
}
#endif#endif //QT_DEPRECATED// 用于在 Qt 的对象模型中进行类型安全的转换。它们是 QObject 类及其派生类之间进行类型转换的工具。
// 模板类型参数 T: 这是一个模板参数,表示要转换的目标类型。
template <class T>
inline T qobject_cast(QObject *object)
{// std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType: 这行代码用于去掉 T 的常量(const)和指针(*)修饰符,得到 ObjType。这是因为 qobject_cast 通常用于去掉类型修饰符后进行实际的转换。typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;// Q_STATIC_ASSERT_X: 这个宏用于静态断言,确保 ObjType 类型确实具有 Q_OBJECT 宏。这个检查是必要的,因为 qobject_cast 依赖于 Qt 的元对象系统来进行类型转换。Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"qobject_cast requires the type to have a Q_OBJECT macro");// ObjType::staticMetaObject.cast(object): 这行代码调用了 ObjType 类的 staticMetaObject 的 cast 方法,该方法是 Qt 元对象系统提供的,用于执行实际的类型转换。cast 方法尝试将 object 转换为 ObjType 类型,如果成功,返回转换后的对象指针;如果失败,返回 nullptr。// static_cast<T>: 最后,使用 static_cast 将 cast 方法的结果转换为模板参数类型 T。return static_cast<T>(ObjType::staticMetaObject.cast(object));
}// const QObject *object: 这个版本接受一个 const QObject * 类型的参数,适用于不能修改的 QObject 指针。
template <class T>
inline T qobject_cast(const QObject *object)
{typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,"qobject_cast requires the type to have a Q_OBJECT macro");return static_cast<T>(ObjType::staticMetaObject.cast(object));
}// 这个模板函数 qobject_interface_iid 返回一个 const char * 类型的指针,指向 Q_NULLPTR(一个宏,通常定义为 nullptr)。它的目的是为接口提供一个默认的接口ID(Interface ID)。对于任何没有特化这个模板的类型,都会返回 Q_NULLPTR。
template <class T> inline const char * qobject_interface_iid()
{ return Q_NULLPTR; }// Q_MOC_RUN 是一个预处理器宏,用来防止 Qt 的元对象编译器(MOC)在处理时包含这段代码。MOC 处理 Qt 的元对象系统,如信号和槽机制,因此在 MOC 运行时,宏中的代码不会被展开。这样可以避免宏展开对 MOC 的干扰。
#ifndef Q_MOC_RUN
// Q_DECLARE_INTERFACE 是一个宏定义,用于声明一个 Qt 接口及其 ID。它通常用于插件的接口定义。
// IFace 是接口类型的名称,IId 是该接口的 ID。
#  define Q_DECLARE_INTERFACE(IFace, IId) \
// 这段代码特化了 qobject_interface_iid 模板函数,使其返回接口的 ID 字符串 IId,这样可以在运行时通过接口 ID 区分不同的接口。template <> inline const char *qobject_interface_iid<IFace *>() \{ return IId; } \
// 这两个特化版本的 qobject_cast 函数尝试将 QObject 对象转换为 IFace 接口类型。如果对象存在并且可以转换,则返回转换后的接口指针;否则返回 Q_NULLPTR。template <> inline IFace *qobject_cast<IFace *>(QObject *object) \{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : Q_NULLPTR)); } \template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \{ return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : Q_NULLPTR)); }
#endif // Q_MOC_RUN#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
#endifclass QSignalBlocker
{
public:inline explicit QSignalBlocker(QObject *o) Q_DECL_NOTHROW;inline explicit QSignalBlocker(QObject &o) Q_DECL_NOTHROW;inline ~QSignalBlocker();#ifdef Q_COMPILER_RVALUE_REFSinline QSignalBlocker(QSignalBlocker &&other) Q_DECL_NOTHROW;inline QSignalBlocker &operator=(QSignalBlocker &&other) Q_DECL_NOTHROW;
#endifinline void reblock() Q_DECL_NOTHROW;inline void unblock() Q_DECL_NOTHROW;
private:Q_DISABLE_COPY(QSignalBlocker)QObject * m_o;bool m_blocked;bool m_inhibited;
};QSignalBlocker::QSignalBlocker(QObject *o) Q_DECL_NOTHROW: m_o(o),m_blocked(o && o->blockSignals(true)),m_inhibited(false)
{}QSignalBlocker::QSignalBlocker(QObject &o) Q_DECL_NOTHROW: m_o(&o),m_blocked(o.blockSignals(true)),m_inhibited(false)
{}#ifdef Q_COMPILER_RVALUE_REFS
QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) Q_DECL_NOTHROW: m_o(other.m_o),m_blocked(other.m_blocked),m_inhibited(other.m_inhibited)
{other.m_o = Q_NULLPTR;
}QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) Q_DECL_NOTHROW
{if (this != &other) {// if both *this and other block the same object's signals:// unblock *this iff our dtor would unblock, but other's wouldn'tif (m_o != other.m_o || (!m_inhibited && other.m_inhibited))unblock();m_o = other.m_o;m_blocked = other.m_blocked;m_inhibited = other.m_inhibited;// disable other:other.m_o = Q_NULLPTR;}return *this;
}
#endifQSignalBlocker::~QSignalBlocker()
{if (m_o && !m_inhibited)m_o->blockSignals(m_blocked);
}void QSignalBlocker::reblock() Q_DECL_NOTHROW
{if (m_o) m_o->blockSignals(true);m_inhibited = false;
}void QSignalBlocker::unblock() Q_DECL_NOTHROW
{if (m_o) m_o->blockSignals(m_blocked);m_inhibited = true;
}namespace QtPrivate {inline QObject & deref_for_methodcall(QObject &o) { return  o; }inline QObject & deref_for_methodcall(QObject *o) { return *o; }
}
#define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1String(#obj))QT_END_NAMESPACE#endif#endif // QOBJECT_H
1、Q_INVOKABLE是什么?
#define Q_INVOKABLE  QT_ANNOTATE_FUNCTION(qt_invokable)

在 Qt 框架中,#define Q_INVOKABLE QT_ANNOTATE_FUNCTION(qt_invokable) 是一个宏定义,用于标记类中的成员函数,使其能够被 Qt 的元对象系统(如信号和槽机制)调用。下面是对这个宏的详细解释:

Q_INVOKABLE

  • 作用Q_INVOKABLE 宏用于标记成员函数,使其能够被 Qt 的元对象系统进行调用。这意味着该函数可以通过 Qt 的信号和槽机制、元对象系统等机制来调用。
  • 语法Q_INVOKABLE 可以用于类中的任意成员函数(包括公有、保护或私有成员函数),使得这些函数可以被 Qt 的 QMetaObject 系统所识别。

QT_ANNOTATE_FUNCTION(qt_invokable)

  • 定义Q_INVOKABLE 宏的实际定义依赖于 QT_ANNOTATE_FUNCTION,这是一个用于标记函数的宏。具体地,QT_ANNOTATE_FUNCTION(qt_invokable) 是一个注解,用于在 Qt 的元对象系统中标识这些函数。
  • 作用QT_ANNOTATE_FUNCTION(qt_invokable) 是一种注释或标记,告知 Qt 的元对象系统该函数具有可调用性。这种标记通常用于代码生成和元对象系统的集成。

在 Qt 的元对象系统中,函数标记为 Q_INVOKABLE 表示该函数可以通过 Qt 的反射机制调用。这对动态调用和信号槽机制至关重要。例如,在信号槽连接过程中,Qt 需要通过反射机制找到并调用相关的槽函数。Q_INVOKABLE 提供了一种方式,使得函数在这种机制中可见并可调用。

通过使用 #define Q_INVOKABLE QT_ANNOTATE_FUNCTION(qt_invokable),Qt 确保了函数标记的一致性和正确性,使得 Qt 的工具和系统能够识别和处理这些函数。

2、同线程内的信号和槽直连接

(1)源码

    /*** @brief connect 函数模板是一个重载版本,它用于连接信号和槽,提供了一个默认的连接类型 (Qt::DirectConnection)。* * @tparam Func1 信号的函数类型。* @tparam Func2 槽的函数类型。* @param sender 信号的发送者对象,类型为 const typename QtPrivate::FunctionPointer<Func1>::Object*。* @param signal 信号的函数指针。* @param slot 槽的函数指针。*/// std::enable_if 用于条件编译。只有当 QtPrivate::FunctionPointer<Func2>::ArgumentCount 大于或等于 0 时,函数模板才有效。// QtPrivate::FunctionPointer<Func2>::ArgumentCount 是 Func2 的参数数量的常量值。template <typename Func1, typename Func2>static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot){// 函数内部调用了另一个 connect 函数模板,传入 Qt::DirectConnection 作为连接类型。// 表示信号和槽都在同一个对象上连接,并且连接类型是 Qt::DirectConnection,即信号和槽在同一个线程中直接调用。return connect(sender, signal, sender, slot, Qt::DirectConnection);}

(2)用法举例
假设你有一个 MyClass 类,其中有一个信号 signal 和一个槽 slot,并且你想连接这两个成员函数,且两者都属于 MyClass 对象。你可以使用这个重载版本的 connect 函数:

MyClass obj;
connect(&obj, &MyClass::signal, &MyClass::slot);
3、QObjectUserData用来设置用户自定义数据

(1)源码

    /*** @brief 注册一个新的用户数据 ID。这个函数通常用于生成一个唯一的 ID,用于后续存储和检索用户数据。* * @return uint 返回一个 uint 类型的唯一 ID,这个 ID 可以用于在对象上存储自定义的数据。*/static uint registerUserData();/*** @brief 为对象设置指定 ID 的用户数据。id 是先前通过 registerUserData() 获取的唯一 ID,data 是要存储的用户数据。* * @param id 用户数据的唯一标识符。* @param data 指向要存储的数据的指针。*/void setUserData(uint id, QObjectUserData* data);/*** @brief 获取与指定 ID 相关联的用户数据。id 是之前用于设置数据的唯一 ID。* * @param id 用于检索之前存储的用户数据,以便在对象的生命周期中访问和使用。* @return QObjectUserData* 返回一个 QObjectUserData* 指针,指向存储的数据。如果指定 ID 没有对应的数据,则返回 nullptr。*/QObjectUserData* userData(uint id) const;

(2)用法

#include <QObject>
#include <QDebug>class CustomData : public QObjectUserData {
public:CustomData(const QString &info) : info(info) {}QString info;
};class MyObject : public QObject {Q_OBJECT
public:MyObject() {// 注册一个新的用户数据 IDuserDataId = registerUserData();}void setCustomData(const QString &info) {CustomData *data = new CustomData(info);setUserData(userDataId, data);}QString getCustomData() {CustomData *data = static_cast<CustomData*>(userData(userDataId));return data ? data->info : "No data";}private:uint userDataId;
};int main() {MyObject obj;obj.setCustomData("Hello, World!");qDebug() << obj.getCustomData(); // 输出 "Hello, World!"return 0;
}

http://www.ppmy.cn/news/1525169.html

相关文章

Leetcode3275. 第 K 近障碍物查询

Every day a Leetcode 题目来源&#xff1a;3275. 第 K 近障碍物查询 解法1&#xff1a;大根堆 维护前 k 小元素&#xff0c;可以用最大堆。 遍历数组 queries&#xff0c;计算点 (x,y) 到原点的曼哈顿距离 d∣x∣∣y∣。 把 d 入堆&#xff0c;如果堆大小超过 k&#xff…

clickhouse 保证幂等性

在分布式数据库系统 ClickHouse 中&#xff0c;幂等性通常涉及到在相同的操作被重复执行时&#xff0c;保证结果不会因为多次执行而发生变化。为了确保幂等性&#xff0c;ClickHouse 采用了一些机制来避免数据重复插入或处理。 以下是 ClickHouse 保证幂等性的一些关键机制&am…

SpringBoot的Web开发支持

使用spring-boot-starter-web启动器&#xff0c;开始web支持&#xff0c;内嵌一个Tomcat&#xff0c;添加了对于SpringMVC的支持。Spring Boot默认servlet容器为tomcat。 常用的服务器配置 配置端口号Spring Boot 默认端口是8080&#xff0c;如果想要进行更改的话&#xff0c;…

使用docker Desktop docker build 报错 无法拉取 nginx 镜像

具体报错信息&#xff1a;ERROR: failed to solve: nginxinc/nginx-unprivileged:alpine: failed to resolve source metadata for docker.io/nginxinc/nginx-unprivileged:alpine: failed to authorize: failed to fetch oauth token: Post "https://auth.docker.io/toke…

支持iPhone 16新品预售,饿了么同步上线专人配送等特色服务

9月10日凌晨&#xff0c;2024年 Apple 秋季新品发布会上正式揭晓iPhone 16新机。9月10日一早&#xff0c;饿了么同步宣布&#xff1a;今年将携手近4000家Apple 授权专营店&#xff0c;支持iPhone 16新品预售及现货的同步开售。新机现货首发当日&#xff0c;饿了么消费者最快半小…

下载docker镜像报错,dial tcp x.x.x.x:443: connect: connection refused

原因是:国外的连接超时了. 解决方案改为阿里云的数据源 打开阿里云 搜索&#xff1a;容器镜像服务 ACR 把你自己的这个直接复制在linux sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF { "registry-mirrors": ["你自己的"] }…

Machine Learning: A Probabilistic Perspective 机器学习:概率视角 PDF免费分享

下载链接在博客最底部&#xff01;&#xff01; 之前需要参考这本书&#xff0c;但是大多数博客都是收费才能下载本书。 在网上找了好久才找到免费的资源&#xff0c;浪费了不少时间&#xff0c;在此分享以节约大家的时间。 链接: https://pan.baidu.com/s/1erFsMcVR0A_xT4fx…

用于客户支持的 GenAI:探索 Elastic Support Assistant

作者&#xff1a;Chris Blaisure, Cory Mangini 我们很高兴地宣布推出 Elastic 的支持助手。本博客将带你了解我们最新的生成式 AI 工具以及它可以帮助你使用 Elastic 技术的一些常见场景。 Elastic 支持助手现已在 Support Hub 上可用 今天&#xff0c;我们宣布 Elastic 支持…

【C++多线程编程】 线程安全与对象生命周期管理

目录 类的线程安全 实现线程安全 构造函数在多线程中的安全性 析构函数多线程环境的安全 智能指针实现多线程安全 shared_ptr 非完全线程安全 shared_ptr可能导致对象生命周期延长 const引用可以减少传递shared_ptr开销 shared_ptr 智能指针块模块的优点 析构所在线程…

【浅谈国产化大数据软件及发展趋势】

1、背景&#xff0c;现状 当下的祖国各方面都在不断成长&#xff0c;有些领域在国际中也占据着重要地位&#xff0c;各个企业如今都在大力的支持国产化的软件&#xff0c;当然国产化的软件就像一个刚成长的孩子&#xff0c;需要给予鼓励和支持&#xff0c;而不是打压。如今企业…

Vue3 响应式工具函数isRef()、unref()、isReactive()、isReadonly()、isProxy()

isRef() isRef()&#xff1a;检查某个值是否为 ref。 isRef函数接收一个参数&#xff0c;即要判断的值。如果该参数是由ref创建的响应式对象&#xff0c;则返回true&#xff1b;否则&#xff0c;返回false。 import { ref, isRef } from vue const normalValue 这是一个普通…

Go 语言的优势

Introduction 概述 This chapter will cover basic concepts of the Go programming language, which will help us to develop our web server application in the later chapters. We will talk and learn about variables, constants, data types (simple and complex ones…

分类预测|基于差分优化DE-支持向量机数据分类预测完整Matlab程序 DE-SVM

分类预测|基于差分优化DE-支持向量机数据分类预测完整Matlab程序 DE-SVM 文章目录 一、基本原理DE-SVM 分类预测原理和流程总结 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 DE-SVM 分类预测原理和流程 1. 差分进化优化算法&#xff08;DE&#xff09; 原理…

顶踩Emlog插件源码

源码介绍 顶踩Emlog插件源码 前些天看到小刀娱乐网的文章页面有了一些变化&#xff0c;那就是增加了一个有价值/无价值的顶踩按钮。 样式也是非常的好看 再加上两个表情包是非常的有趣。 写到了Emlog系统&#xff0c;效果如上图。 如何使用&#xff1a; 需要在echo_log.…

小程序给对象赋值(双向绑定)方法之一

场景&#xff1a;在我编辑表单的时候&#xff0c;希望将数据同步到最终提交的表单对象数据中&#xff0c;这里用的是vantUI的 van-field 组件 wxml&#xff1a; <van-field model:value"{{loginParams.username}}" clearable placeholder"输入账号或手机号码…

走进低代码表单开发(一):可视化表单数据源设计

在前文&#xff0c;我们已对勤研低代码平台的报表功能做了详细介绍。接下来&#xff0c;让我们深入探究低代码开发中最为常用的表单设计功能。一个完整的应用是由众多表单组合而成的&#xff0c;所以高效的表单设计在开发过程中起着至关重要的作用。让我们一同了解勤研低代码开…

MongoDB延迟查询

在 MongoDB 中&#xff0c;查看副本集成员之间的副本延迟可以通过以下步骤进行&#xff1a; 使用 rs.status() 命令&#xff1a; 这个命令提供了副本集的详细状态信息&#xff0c;包括每个成员的延迟情况。在 MongoDB shell 中&#xff0c;你可以执行以下命令&#xff1a; rs.s…

从搜索热度上看Arcgis的衰退

Arcgis已被qgis快速赶上 google trends是一个google综合了每日的搜索情况的统计网站&#xff0c;可以追踪从2004年开始各个关键字的搜索热度。 我用arcgis和qgis作为对比&#xff0c;简单探索了arcgis和qgis的全球相关热度。 假设&#xff0c;搜索arcgis越高的区域&#xff…

一文教你弄懂网络协议栈以及报文格式

文章目录 OSI七层网络协议栈示意图1. 应用层&#xff08;Application Layer&#xff09;2. 表示层&#xff08;Presentation Layer&#xff09;3. 会话层&#xff08;Session Layer&#xff09;4. 传输层&#xff08;Transport Layer&#xff09;5. 网络层&#xff08;Network …

深入理解全连接层:从线性代数到 PyTorch 中的 nn.Linear 和 nn.Parameter

文章目录 数学概念&#xff08;全连接层&#xff0c;线性层&#xff09;nn.Linear()nn.Parameter()Q1. 为什么 self.weight 的权重矩阵 shape 使用 ( out_features , in_features ) (\text{out\_features}, \text{in\_features}) (out_features,in_features)而不是 ( in_featur…