当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > signal&slot连接过程

signal&slot连接过程 时间:2018-09-26      来源:未知

信号&槽连接过程分析

通过Q_OBJECT 宏在编译过程中产生的Moc文件我们已经分析过了。那么QObject是如何通过Moc建立信号&槽之间的绑定的呢?

1 友元

大家可以看到QMetaObject是QObject的友元,那么就意味着可以访问生成的Moc文件中的友元的成员函数和数据成员,QObject就是这样来获取信号&槽在Moc文件中的相对索引、参数类型、参数名、函数名等信号或槽的调用与绑定所需要的关键信息。

二 信号&槽连接过程

信号&槽连接关键调用流程如图:

首先要说清QMetaObjectPrivate数据的由来,然后才能根据调用的序号进行一步一步的说明,QMetaObjectPrivate从何处来?

const QMetaObject CTestMoc::staticMetaObject = {

{ &QObject::staticMetaObject, qt_meta_stringdata_CTestMoc.data,

qt_meta_data_CTestMoc, qt_static_metacall, 0, 0}

};

在初始化这个结构体时,大家注意到第三个参数qt_meta_data_CTestMoc对应的是const uint *data 这个类型,而QMetaObjectPrivate就是由这个数据转换而来,前14个uint保存了这个信号&槽的索引位置、个数、信号个数等信息。而connect这个函数获取信号的索引以及接收方槽的相对索引皆是通过QMetaObjectPrivate这个对象获取。

下面,根据调用序号进行说明。

1 QObject的connect函数。

这个函数是建立两个对象的信号或槽连接调用的函数,由于传递的对象是QObject类型指针、信号或槽的参数是通过调用宏返回的字符串,信号或槽的索引也是通过QMetaObjectPrivate获取,所以,QObject对象与子类的耦合度很低。

2 QMetaObjectPrivate::decodeMethodSignature 获取信号名和格式化信号参数

这个函数主要作用是返回信号或槽名称和信号或槽参数组成的一个”数组”

(1) 信号或槽函数名获取

信号或槽函数名是取SIGNAL或SLOT宏返回的字符串 ‘(’ 字符前所有字符组成的字符串。

(2) 信号或槽参数类型处理 QArgumentTypeArray

参数类型处理的原理是根据逗号分隔匹配的是括号内的字符串,然后根据类型的字符串初始化QArgumentType类型对象,后保存在QArgumentTypeArray中,QArgumentTypeArray这个对象通过一个指针指向一个malloc分配的数组,而数组类型就是QArgumentType。

3 QMetaObjectPrivate::indexOfSignalRelative 获取相对索引

在Moc文件的索引表中已经初始化好了信号&槽的索引、参数、类型等信息,在获取相对索引过程中,检查QMetaObjectPrivate::decodeMethodSignature函数整理的信号或槽信息的入参是否正确就是匹配与Moc文件中信号或槽信息是否一致。

4 QMetaObjectPrivate::signalOffset 计算绝对索引

在构建staticMetaObject 静态成员时,参数QObject::staticMetaObject是QObject的静态元对象,而绝对索引就是元对象的superdata信号数量加上子类的信号的相对索引。

QMetaObjectPrivate::signalOffset函数计算索引的关键代码如下:

for (m = m->d.superdata; m; m = m->d.superdata)

offset += priv(m->d.data)->signalCount;

5 QMetaObjectPrivate::decodeMethodSignature 获取槽函数名和格式化槽参数

处理方式同第二步函数调用。

6 QMetaObjectPrivate::indexOfSlotRelative 获取槽函数相对索引

获取索引原理同获取信号索引原理一致

7 QMetaObject::Connection 建立连接

这个函数是QMetaObject::Connection调用QMetaObjectPrivate::connect实现的。

建立连接主要的两个过程是创建连接的关键,第一个是连接结构体赋值,第二个是连接结构体插入链表处理,其中链表处理尤为关键。

(1) 创建结构体

QScopedPointer c(new QObjectPrivate::Connection);

c->sender = s; 发送信号对象

c->signal_index = signal_index; 信号绝对索引

c->receiver = r; 接收对象

c->method_relative = method_index; 槽索相对引

c->method_offset = method_offset; 槽绝对索引的偏移量,与信号绝对索引计算方式相同

c->connectionType = type;

c->isSlotObject = false;

c->argumentTypes.store(types);

c->nextConnectionList = 0;

c->callFunction = callFunction; 回调函数staticMetaObject中的qt_static_metacall

这个就是结构体的赋值,从中可以看出QObject对象是根据索引来调用处理信号和槽的调用。

(2) 插入链表

ConnectionList &connectionList = (*connectionLists)[signal];

首先,在发送对象的连接列表里尾部插入QObjectPrivate::Connection对象

if (connectionList.last) {

connectionList.last->nextConnectionList = c;

} else {

connectionList.first = c;

}

connectionList.last = c;

cleanConnectionLists();

其次,在接受对象首部插入QObjectPrivate::Connection对象

c->prev = &(QObjectPrivate::get(c->receiver)->senders);

c->next = *c->prev;

*c->prev = c;

if (c->next)

c->next->prev = &c->next;

上一篇:scanf函数

下一篇:用户级线程和内核级线程

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部