读QT5.7源码(七)QObjectData 和 QObjectPrivate

2023-11-12

在QObject中定义了一个保护权限的成员变量 d_ptr
protected:
    QScopedPointer<QObjectData> d_ptr;


QScopePointer<> 是一个模板类,维护特定类型的指针,这里d_ptr  相当于一个QObjectData对象的指针。

QObject 几乎是所有QT中的类的基类,因此QT中每个继承于Qobject的类都有这个指针,指向一个动态分配的QObjectData对象。


QObjectData类的定义


class Q_CORE_EXPORT QObjectData {
public:
    virtual ~QObjectData() = 0;
    QObject *q_ptr;    对象this指针
    QObject *parent;   父对象指针
    QObjectList children;       typedef QList<QObject*> QObjectList;     这个是对象的子对象链表,区别于父类和子类

    uint isWidget : 1;   是否是Wideget类型
    uint blockSig : 1;      是否处于信号阻塞
    uint wasDeleted : 1;     防止多次delete对象
    uint isDeletingChildren : 1;   是否在delete子对象
    uint sendChildEvents : 1;       是否向父对象报告对象插入和删除事件  应该为true
    uint receiveChildEvents : 1;     是否接收子对象的事件消息    应该为ture
    uint isWindow : 1; //for QWindow
    uint unused : 25;
    int postedEvents;
    QDynamicMetaObjectData *metaObject;
    QMetaObject *dynamicMetaObject() const;
};



在QObject的构造函数中对d_ptr进行了初始化


QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)     这里是构建了一个QObjectPrivate对象,并将其指针赋给d_ptr
{
....................................省略
}


QObjectPrivate  是QObjectData的子类,这样就合情合理了。 事实上这个类是如此的重要,也是信息量很大的一个结构


class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)

public:
    struct ExtraData
    {
        ExtraData() {}
    #ifndef QT_NO_USERDATA
        QVector<QObjectUserData *> userData;
    #endif
        QList<QByteArray> propertyNames;
        QVector<QVariant> propertyValues;
        QVector<int> runningTimers;
        QList<QPointer<QObject> > eventFilters;
        QString objectName;
    };                              //一些结构分别用来存放对象所属类的 property 运行时间等信息

    typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
    struct Connection    //重要的结构   保存每个信号和槽的连接
    {
        QObject *sender;    发送对象的指针
        QObject *receiver;   接受对象的指针
        union {
            StaticMetaCallFunction callFunction;         接受对象的qt_static_metacall函数的指针
            QtPrivate::QSlotObjectBase *slotObj;
        };
        // The next pointer for the singly-linked ConnectionList
        Connection *nextConnectionList;   
        //senders linked list
        Connection *next;
        Connection **prev;
        QAtomicPointer<const int> argumentTypes;     参数值数组指针
        QAtomicInt ref_;
        ushort method_offset;    
        ushort method_relative;   
        uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
        ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
        ushort isSlotObject : 1;
        ushort ownArgumentTypes : 1;
        Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) {
            //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
        }
        ~Connection();
        int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
        void ref() { ref_.ref(); }
        void deref() {
            if (!ref_.deref()) {
                Q_ASSERT(!receiver);
                delete this;
            }
        }
    };
    // ConnectionList is a singly-linked list   信号对应的槽链表,每一个信号对应一个该结构,每一个连接保存在一个connection
    struct ConnectionList {
        ConnectionList() : first(0), last(0) {}
        Connection *first;
        Connection *last;
    };

    struct Sender   
    {
        QObject *sender;
        int signal;
        int ref;
    };


    QObjectPrivate(int version = QObjectPrivateVersion);
    virtual ~QObjectPrivate();
    void deleteChildren();

    void setParent_helper(QObject *);
    void moveToThread_helper();
    void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
    void _q_reregisterTimers(void *pointer);

    bool isSender(const QObject *receiver, const char *signal) const;
    QObjectList receiverList(const char *signal) const;
    QObjectList senderList() const;

    void addConnection(int signal, Connection *c);
    void cleanConnectionLists();

    static inline Sender *setCurrentSender(QObject *receiver,
                                    Sender *sender);
    static inline void resetCurrentSender(QObject *receiver,
                                   Sender *currentSender,
                                   Sender *previousSender);

    static QObjectPrivate *get(QObject *o) {
        return o->d_func();
    }

    int signalIndex(const char *signalName, const QMetaObject **meta = 0) const;
    inline bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
    inline bool isDeclarativeSignalConnected(uint signalIdx) const;

    // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
    // the API public in QObject. This is used by QQmlNotifierEndpoint.
    inline void connectNotify(const QMetaMethod &signal);
    inline void disconnectNotify(const QMetaMethod &signal);

    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 *receiverPrivate, Func2 slot,
                                                  Qt::ConnectionType type = Qt::AutoConnection);

    template <typename Func1, typename Func2>
    static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
                                  const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);

    static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
                                               const QObject *receiver, void **slot,
                                               QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
                                               const int *types, const QMetaObject *senderMetaObject);
    static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
    static bool disconnect(const QObject *sender, int signal_index, void **slot);
public:
    ExtraData *extraData;    // extra data set by the user
    QThreadData *threadData; // id of the thread that owns the object

    QObjectConnectionListVector *connectionLists;

    Connection *senders;     // linked list of connections connected to this object
    Sender *currentSender;   // object currently activating the object
    mutable quint32 connectedSignals[2];

    union {
        QObject *currentChildBeingDeleted;
        QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
    };

    // these objects are all used to indicate that a QObject was deleted
    // plus QPointer, which keeps a separate list
    QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
};

其中 QObjectConnectionListVector *connectionLists    是一个QVector<QObjectPrivate::ConnectionList>



class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
    bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
    bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
    int inUse; //number of functions that are currently accessing this object or its connections
    QObjectPrivate::ConnectionList allsignals;

    QObjectConnectionListVector()
        : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
    { }

    QObjectPrivate::ConnectionList &operator[](int at)
    {
        if (at < 0)
            return allsignals;
        return QVector<QObjectPrivate::ConnectionList>::operator[](at);
    }
};



结构图如下






1、QObjectList QObjectPrivate::receiverList(const char *signal) const    返回指定信号关联的接受对象的列表

QObjectList QObjectPrivate::receiverList(const char *signal) const
{
    Q_Q(const QObject);
    QObjectList returnValue;
    int signal_index = signalIndex(signal);   返回绝对索引
    if (signal_index < 0)
        return returnValue;
    QMutexLocker locker(signalSlotLock(q));
    if (connectionLists) {
        if (signal_index < connectionLists->count()) {
            const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;  根据索引在QVector中找到对应的ConnectionList,first指向表头

            while (c) {
                if (c->receiver)
                    returnValue << c->receiver;
                c = c->nextConnectionList;    遍历这个单项链表,将receiver不为空的添加到QObjectList
            }
        }
    }
    return returnValue;
}


2、QObjectList QObjectPrivate::senderList() const   返回链接到改对象的  对象列表


QObjectList QObjectPrivate::senderList() const
{
    QObjectList returnValue;
    QMutexLocker locker(signalSlotLock(q_func()));
    for (Connection *c = senders; c; c = c->next)
        returnValue << c->sender;                       通过遍历senders
    return returnValue;
}

3、int QObjectPrivate:: signalIndex  const char *signalName,const QMetaObject **meta) const      返回信号的绝对索引


int QObjectPrivate::signalIndex(const char *signalName,
                                const QMetaObject **meta) const
{
    Q_Q(const QObject);  //宏 q=this
    const QMetaObject *base = q->metaObject();
    Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
    QArgumentTypeArray types;
    QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);  
    int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
            &base, name, types.size(), types.constData());
    if (relative_index < 0)
        return relative_index;
    relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
    if (meta)
        *meta = base;
    return relative_index + QMetaObjectPrivate::signalOffset(base);     +offset   返回绝对索引    索引相对于全部的信号包括继承来的
}



4、void QObjectPrivate:: addConnection (int signal, Connection *c)    将某个信号关联的Connection  加到链表中

void QObjectPrivate::addConnection(int signal, Connection *c)
{
    Q_ASSERT(c->sender == q_ptr);
    if (!connectionLists)
        connectionLists = new QObjectConnectionListVector();   如果容器为空创建它
    if (signal >= connectionLists->count())
        connectionLists->resize(signal + 1);                 根据信号的索引,如果容器对应的索引位置为空,表示还没有为信号连接任何函数,调整容器大小,
                                                              在对应的位置构建信号关联的ConnectionList
    ConnectionList &connectionList = (*connectionLists)[signal];
    if (connectionList.last) {
        connectionList.last->nextConnectionList = c;
    } else {
        connectionList.first = c;   
    }
    connectionList.last = c;      //.last始终指向最后加入的connection

    cleanConnectionLists();

    c->prev = &(QObjectPrivate::get(c->receiver)->senders);
    c->next = *c->prev;
    *c->prev = c;                               //加到接收对象的senders的链表里
    if (c->next)
        c->next->prev = &c->next;

    if (signal < 0) {
        connectedSignals[0] = connectedSignals[1] = ~0;
    } else if (signal < (int)sizeof(connectedSignals) * 8) {
        connectedSignals[signal >> 5] |= (1 << (signal & 0x1f));
    }
}





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

读QT5.7源码(七)QObjectData 和 QObjectPrivate 的相关文章

  • QGraphicsScene没有删除QWidget的功能

    QGraphicsScene 有一个addWidget QWidget 有函数 但是没有对应的removeWidget QWidget 它只有removeItem QGraphicsItem 如何删除 QWidget 这是一个基本示例 看看
  • 如何在Qt无框窗口中实现QSizeGrip?

    如何使用 Qt 无框窗口实现 QSizeGrip 代码会是什么样的 您只需在布局内窗口的一角添加 QSizeGrip 即可使其保持在该角落 QDialog dialog new QDialog 0 Qt FramelessWindowHin
  • QPainter 性能高帧率

    我试图在 QPainter 中以 60fps 的速度显示视频 在 OpenGLwidget 中 我遇到一个问题 有时绘图花费的时间太长 并且在使用 QPainter 时发生下一个重绘事件 这会生成警告和随机崩溃 有几个问题 是否有一种 Qt
  • 如何从浮点数组创建新的 QImage

    我有一个代表图像的浮点数数组 列在前 我想在 QGraphicsSecene 上将图像显示为 QPixmap 为了做到这一点 我尝试使用 QImage 构造函数 QImage const uchar data int width int h
  • 我应该使用 QCoreApplication::processEvents() 还是 QApplication::processEvents()?

    我有一个从两者调用的方法QThreads和主线程 这个方法有时可能需要很长时间才能在循环中进行计算 所以我把QCoreApplication processEvents 这可以防止 GUI 冻结 在某个时刻我已经改变了QCoreApplic
  • PyQt - 如何从给定的小部件获取顶级父级?

    给定的小部件如何访问它最旧的父级 即顶级小部件 我需要 showMinimized it 现在我正在使用 self parent parent parent showMinimized 但这似乎不是最好的方法 如果它移动了 我需要手动更改父
  • 使用 QTextCursor 选择一段文本

    使用 Qt 框架选择文本片段时遇到问题 例如 如果我有这个文件 没有时间休息 我想选择 ime for r 并从文档中删除这段文本 我应该如何使用 QTextCursor 来做到这一点 这是我的代码 QTextCursor cursor n
  • 在哪里可以找到 QT 5.3.0 命令提示符

    用于学习Qt的书 C gui programming with qt 4 2nd 版 我需要Qt的命令提示符 我已经安装了Qt 5 3 0 creator 5 3 0开源 但不知道它的命令提示符在哪里 有人可以帮助我吗 我认为您正在寻找的是
  • 如何在 QT 中绘制点?

    我正在用 QT 用 C 编写一个应用程序 其中有 n 个点并计算它的凸包 然而 一旦计算出来 我不知道如何绘制点并绘制船体的边界 制作菜单按钮等很简单 但我不确定我是否知道执行此操作的工具 你怎么做到这一点 图形视图 addEllipse
  • 有没有办法向 QListView 添加部分?

    我正在使用 Qt5 2 和 C 来实现一个应用程序 需要显示一个列表 其中包含类似于下面的示例图像的部分 source ngo hung com http www ngo hung com files images contact list
  • Qt qDebug() 在 Windows shell 中不起作用

    我正在使用一个qDebug Qt 框架的printf屏幕上有东西 当我从 Qt Creator 运行应用程序时它工作得很好 但是当我尝试从 Windows 执行它时cmd它什么也没显示 为什么会发生这种情况 你必须添加 CONFIG con
  • 在 Qt 服务器上验证用户身份

    我正在尝试使用 C QtTcpSocket 为个人项目 多人国际象棋游戏 实现身份验证系统 我的朋友建议了一种验证用户的方法 但我想问是否有更简单或更好的方法 来自 Python 背景 做这个项目主要是为了加深对 C 的理解 我将发布我朋友
  • QComboBox 下拉项边距

    我想设计我的风格QComboBox为下拉项目留出边距 现在是这样的 我想要这样的东西 我尝试过 QComboBox QAbstractItemView item margin 3px 但它不起作用 你能帮我解决这个问题吗 您想在项目之间设置
  • QStyledItemDelegate 绘制自定义小部件失败

    在我的一个项目中 我使用的是QTableWidget为了显示一些复杂的计算结果 为了提高表格的可读性 我需要在单个表格单元格内显示两个对齐的值 后来我想通过使用颜色或箭头等来进一步自定义小部件 为此我源自QStyledItemDelegat
  • QT:删除QGridLayout中QLabel之间的空格

    我将一些具有不同颜色的 QLabels 添加到 QGridLayout 作为 QWidget 的布局 现在我在每个 Qlabel 与下一个 Qlabel 之间有一个间距 我想将其删除 我尝试将标签的边距设置为 0 将 GridLayout
  • 使用 CMake 编译时更改头文件位置会导致缺少 vtable 错误

    对于一个大型 C 项目 我需要从 qmake 过渡到 CMake 但是在处理一个玩具示例时 我遇到了一些我不理解的行为 示例代码具有单个头文件 当该头文件移动到子目录中时 我收到 MainWindow 类缺少 vtable 的错误 CMak
  • 如何在Qt 5中的paintEvent上使用mouseMoveEvent?

    我是 Qt 和 c 的新手 所以我遇到了一些困难 我正在尝试创建一个小部件 它可以获取 mouseMoveEvent 位置并在鼠标位置的像素图上绘制椭圆 下面你可以看到代码 include myimage h include
  • 是否有 Qt 小部件可以浏览应用程序中小部件的层次结构(类似于 Spy++)?

    我们有一个具有复杂的小部件层次结构的应用程序 我希望能够以与 Spy 类似的方式浏览此层次结构 查看和编辑属性 例如大小 如果有一个小部件可以显示此信息 则它不需要在外部应用程序中运行 那么问题来了 这样的神兽存在吗 您可以使用Gammar
  • 使用 QGraphicsScene 实现流畅的动画

    我希望我的问题并不总是同样的问题 我有一个 QGraphicsScene 它的项目是一些 QGraphicsPixmap 我用一个计时器来移动它们 每秒 SetX 10 我设置 10是因为窗口大100 使用这个解决方案我的动画不流畅 我想我
  • QFileSystemModel setRootPath

    我正在尝试创建一个 Qt 应用程序来显示文件夹 Mac OS 中的 Users 文件夹 的内容 这是代码 QFileSystemModel dirModel new QFileSystemModel dirModel gt setRootP

随机推荐

  • 使用Jenkins配置自动化构建

    原文地址 http blog csdn net littlechang article details 8642149 下载jenkins http mirrors jenkins ci org war 列出了jenkins的所有relea
  • C语言之完数、素数、回文数合集

    1 完全数 Perfect number 又称完美数或完备数 是一些特殊的自然数 它所有的真因子 即除了自身以外的约数 的和 即因子函数 恰好等于它本身 如果一个数恰好等于它的因子之和 则称该数为 完全数 第一个完全数是6 第二个完全数是2
  • MATLAB中定义数组序列,matlab怎么定义一个数组

    A n input n 数组的长度 for i 1 n fprintf a 0f i x input 分别输入各个数的值 A A x end A 就可以得到长度为n的数组了 建议在一开始就定义数组大小 这样可以减少内存的使用 同时加快计算速
  • List of default Mac OS X command-line editing bash keyboard shortcuts

    本文转载至 https maymay net blog 2007 07 18 list of default mac os x command line editing bash keyboard shortcuts More and mo
  • aspose 转pdf表格大小乱了_C#使用 aspose 从excel转成pdf,用矩阵处理其中的签章图片大小和位置...

    实例简介 C 使用 aspose 从excel转成pdf 用矩阵处理其中的签章图片大小和位置 实例截图 核心代码 public Stream ExcelToPdf Stream sm excel Stream sm Re new Memor
  • 16.网络爬虫—字体反爬(实战演示)

    网络爬虫 字体反爬 一 字体反爬原理 二 字体反爬模块Fonttools TTF文件 三 FontCreator 14 0 0 2790 FontCreatorPortable下载与安装 四 实战演示 五 后记 前言 个人简介 以山河作礼
  • LLVM查缺补漏-2

    Mailing Lists 邮件列表有两种基本形式 公告型 邮件列表 通常由一个管理者向小组中的所有成员发送信息 如电子杂志 新闻邮件等 讨论型 讨论组 所有的成员都可以向组内的其他成员发送信息 其操作过程简单来说就是发一个邮件到小组的公共
  • Java-接口

    Java 接口 1 概念 接口和类是平级的关系 举例以下 学习就是一个接口 可以飞 攻击性都是接口 2 接口的使用 接口使用interface关键词来定义 定义接口的结构 JDK1 7及以前 只能全局常量和抽象方法 全局常量 public
  • 用Groovy写Servlet

    本文参考自Servlet support 大部分代码引用了原文档 快速开始 Groovy语言提供了一个模块 可以让我们写用Groovy脚本的方式来编写Servlet 这叫做Groovlets 先看看一个简单的例子吧 下面这几个例子都来自官方
  • webpack&vite

    webpack支持多模块化 可以跑在服务端 一开始就要同一模块化代码 所以他需要把所有依赖读取一遍 并且转化为对应的代码 然后再去开启开发服务器 ast抽象语法分析工具 分析你写的文件有啥导入导出 vite只支持es module 只跑在浏
  • 五个温度带的分界线_中国划分为哪五个个温度带

    展开全部 在我国 从北到南习惯上划分为寒温带 中温带 暖温62616964757a686964616fe59b9ee7ad9431333366303732带 亚热带 热带 1 秦岭淮河线以南 主要是我国的亚热带和热带地区 一般亚热带位于温带
  • qt编写的简单日历控件lan2calendar

    使用中的一些bug可以反馈一下 项目地址 https gitee com mengtianwxs lan2calendar
  • 论文笔记:Autoregressive Tensor Factorizationfor Spatio-temporal Predictions

    0 摘要 张量因子tensor factorization分解方法在时空数据分析领域很受欢迎 因为它们能够处理多种类型的时空数据 处理缺失值 并提供计算效率高的参数估计程序 然而 现有的张量因子分解方法并没有尝试学习空间自相关 这些方法使用
  • snprintf函数和sprintf函数

    今天写代码 做字符串处理 写了以下语句 snprintf loginTime sizeof loginTime s s loginTime blankSpace 然后loginTime中的字符串老不对 记得以前用sprintf的时候 类似语
  • CISCN部分WP-ukfc

    WP ukfc 讲个笑话 华北19进不了决赛 再讲个笑话 27号黑灯 国粹过了300出头 努什么力 不如去海鲜市场 Web unzip L zip bello var www html R zip bello bello php 先传入L文
  • 51单片机在中断响应时,系统不能自动清除哪些中断请求标志?编程时应如何处理?...

    51单片机在中断响应时 系统不会自动清除中断请求标志 因此 程序员需要在编写的中断服务程序中手动清除相应的中断请求标志 这可以通过使用汇编指令或 C 语言函数来实现 在汇编语言中 可以使用 CLR bit 指令来清除某一位 在 C 语言中
  • linux中$0、$?、$*、$@、$#、$$

    0 shell脚本名 1 执行shell脚本传的第一个参数 n 第n个参数 上一条命令的执行状态 0为成功 执行shell脚本传的所有参数 同上 所在命令的PID test sh bin sh echo hello echo filenam
  • 接口测试全流程总结

    接口测试全流程扫盲 接口测试全流程扫盲 扫盲内容 1 什么是接口 2 接口都有哪些类型 3 接口的本质是什么 4 什么是接口测试 5 问什么要做接口测试 6 怎样做接口测试 7 接口测测试点是什么 8 接口测试都要掌握哪些知识 9 其他相关
  • 二进制补码的理解

    正数的原码 反码 补码 负数的原码 反码 补码关系为 原码 正数的原码符号位变为1 反码 正数的原码取反 补码 正数的原码取反加1 补码主要为了计算机进行减法运算 参考1 https www cnblogs com guanjianzhuo
  • 读QT5.7源码(七)QObjectData 和 QObjectPrivate

    在QObject中定义了一个保护权限的成员变量 d ptr protected QScopedPointer