emit,幕后的故事
当我们写下一下emit signal代码的时候,与这个signal相连接的slot就会被调用,那么这个调用是如何发生的呢?
让我们来看一段例子代码:
class ZMytestObj : public QObject
{
Q_OBJECT
signals:
void sigMenuClicked();
void sigBtnClicked();
};
MOC编译器在做完预处理之后的代码如下:
// SIGNAL 0
void ZMytestObj::sigMenuClicked()
{
QMetaObject::activate(this, &staticMetaObject, 0, 0);
}
// SIGNAL 1
void ZMytestObj::sigBtnClicked()
{
QMetaObject::activate(this, &staticMetaObject, 1, 0);
}
每一个signal都会被转换为一个与之相对应的成员函数。也就是说,当我们写下这样一行代码:
emit sigBtnClicked();
当程序运行到这里的时候,实际上就是调用了void ZMytestObj::sigBtnClicked() 这个函数。大家注意比较这两个函数的函数体,
void ZMytestObj::sigMenuClicked() void ZMytestObj::sigBtnClicked(),
它们唯一的区别就是调用 QMetaObject::activate 函数时给出的参数不同,一个是0,一个是1,它们的含义是什么呢?
它们表示是这个类中的第几个signal被发送出来了,回头再去看头文件就会发现它们就 是在这个类定义中,signal定义出现的顺序,这个参数可是非常重要的,它直接决定了进入这个函数体之后所发生的事情。
当执行流程进入到QMetaObject::activate函数中后,会先从connectionLists(这个变量根据传入的signal的index将每个signal对应的connectionList都包含进来)这个变量中取出与这个signal相对应的 connection list,它根据的就是刚才所传入进来的signal index。这个connectionlist中保存了所有和这个signal相链接的slot的信息,每一对connection(即:signal 和 slot 的连接)是这个list中的一项。
在每个一具体的链接记录(connectionList)中,还保存了这个链接的类型,是自动链接类型,还是队列链接类型,或者是阻塞链接类型,不同的类型处理方法还不一样的。这里,我们就只说一下直接调用的类型。
对于直接链接的类型,先通过connectionList找到接收这个signal的对象的指针,然后通过这个对象指针找到处理这个signal的slot的index(这个index表示是这个对象中slot的索引),已经是否有需要处理的参数,然后就使用这些信息去调用receiver的qt_metcall 方法。
在qt_metcall方法中就简单了,根据slot的index,一个大switch语句,调用相应的slot函数就OK了。
<
QT一些细节内幕
最新推荐文章于 2022-09-11 18:12:33 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)