接上文:从零开始实现信号槽机制:一
关于Qt的信号槽机制,How Qt Signals and Slots Work是一篇特别好的文章,在此对作者表示感谢。
好了,是时候写段Qt代码看看了,这是一段典型的使用Qt信号槽的代码,因为我们这段代码直接写在main.cpp里面,所以在最后记得加上#include "main.moc":
#include <iostream>
#include <QApplication>
using namespace std;
class Button : public QObject
{
Q_OBJECT
public:
void nowClick(bool b) { emit click(b); }
signals:
void click(bool);
};
class Tv : public QObject
{
Q_OBJECT
public:
Tv(int b, int t) : bootTime(b), offTime(t){}
protected slots:
void onStateChanged(bool b)
{
if ( b == true )
cout << "Tv is being turned on. bootTime is " << bootTime << endl;
else
cout << "Tv is being turned off. offTime is " << offTime << endl;
}
private:
int bootTime;
int offTime;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Button btn;
Tv tv(10, 20);
QObject::connect(&btn, SIGNAL(click(bool)), &tv, SLOT(onStateChanged(bool)));
btn.nowClick(true);
return a.exec();
}
#include "main.moc"
我们知道Qt源代码在make之前需要先进行一道qmake,而qmake会调用moc.exe这个“元对象编译器”来对包含Q_OBJECT宏的文件进行一个预处理,要弄清Qt的信号槽如何运作,首先我们得知道signals,slots这种不符合C++规范的东西到底被处理成了什么鬼,ok,我们在qobjectdefs.h里面找到它们了:
#define slots
#define signals public // Qt5 中由 protected 改为 public 以支持更多特性
#define emit
#define SLOT(a) "1"#a
#define SIGNAL(a) "2"#a
当然这些定义在某些情况下,比如定义了QT_NO_EMIT时会不同,不过这超出了本文的讨论范围,大家有兴趣可以去读下源码。好的,现在我们知道了,“slots”和“emit”根本就是两个空宏,而signals仅仅是一个public,这样看来,Qt中的信号是个真正的函数无疑,而不是像sigslot中以functor的方式实现。connect函数则是借助SIGNAL和SLOT两个宏为信号和槽函数添加了一个数字并将其转化成字符串,也就是说,上面的main()中的connect实际等价于:
QObject::connect(&btn, "2click(bool)", &tv, "1onStateChanged(bool)");