您的位置:首页 > 编程语言 > Qt开发

深入理解QT的SIGNAL\SLOT机制(五):信号的发射过程

2017-12-20 11:40 771 查看
我们来看信号的发起过程,先来看一个宏定义:
# define emit
,这个宏定义将emit定义为空,也就是说你在emit mysignal()的时候,这行代码其实就是mysignal(),所以信号就是函数,只是换了个概念而已!

废话不多说,来DEBUG:



我们在11行打断点F11进入:

// SIGNAL 0
void MyWidget::mysignal()
{
QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}


居然直接调用了moc文件中的mysignal函数,现在是不是更清楚信号就是函数了啊?这里的this是MyWidget对象,staticMetaObject就是第二章提到的静态QMEtaObject,其余都是空。进入active函数之前回去先计算偏移量:



822~824行:将QMetaObject的所有父类偏移量加起来,目的是找到子类的第一个信号的偏移量(5.9.1中除了类名信息之外,只存储了信号和槽的信息)。现在进入active函数:



3636行:子类第一个信号的偏移量+当前偏移量,就是我们需要的mysignal信号的偏移量。

3637~3660行:进行安全检查,检查是否绑定信号和槽。

接着来看:



3694行:根据信号的signal_index下标查找到connectionList,这个connectionList存储的是所有绑定到该信号的槽函数信息;



3700~3705行:拿到列表的first和last,进行遍历。

3707~3709行:receiver是空,就意味着没有槽函数,continue;

3712~3721行:针对不同类型进行不同的处理;

我们的是在统一个线程中,调用3743行的switchSender函数,不同线程的是放到队列中去;



来看switchSender函数:

inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id)
{
this->receiver = receiver;
currentSender.sender = sender;
currentSender.signal = signal_absolute_id;
currentSender.ref = 1;
previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender);
switched = true;
}


发现该函数基本是进行值拷贝,继续来看active函数:

3757~3766行:如果c->callFunction不为空,并且c->methodOffset在QMetaObject的methodOffset之内(保证调用的函数偏移量不超过QMetaObject的偏移量),就可以调用callFunction.

我们看到
const auto callFunction = c->callFunction;


callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);


实际上就是在调用callFunction,也就是moc_test.cpp中的qt_static_metacall函数。

调用完之后继续执行do{}while(),知道所有的槽被调用。

接下来按F11,进入callFunction



可以看到确实调用了moc_test.cpp中的static_metacall函数,

71行:格局传入的id调用对应的槽函数,所以myslot被调用。

OK,完结撒花!

如有问题欢迎指正

电子科技大学

胡力卫

15373632531@163.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  qt SLOT SIGNAL