目录
前言:
信号和槽初识
两个问题
前言:
本文我们正式开始介绍信号与槽这个概念,在谈及Qt中的信号与槽这个概念之前,我们不妨回顾一下Linux中的信号,比如发生了除0错误,OS就会给该进程发送一个信号,使该进程终止。
那么Linux中涉及信号的时候,涉及到了谁发出的,什么信号,执行的行为,谁接受的。在我们前文熟悉Qt的整个框架的时候,使用的函数connect,参数分别就是上面涉及到了四个点,所以实际上Qt中的信号和Linux中的信号是有很多相同点的,那么有了Linux的基础,在这里学习Qt我们就要轻松很多了。
信号和槽初识
说到底,我们现在还是没有理解什么是槽,什么是信号,这里先给一个结论:
信号和槽都是函数
但是,为什么信号是函数这里并不打算展开来说,我们在这里能理解的是槽是函数,那么也就是说,某个控件接收到了某个信号,就要执行对应的槽函数,那么我们为什么控件知道接收到了某个信号就应该执行某个槽函数呢?
这是因为connect将槽函数和信号关联在了一起。
那么槽和信号的触发顺序是什么呢?我们不妨举个女朋友在一个月中总有那么不舒服的几天,当我们接收到了女朋友不舒服的这个信号,我们就应该知道我们该倒红糖水,该揉揉肚子什么的。
所以对于信号和槽的一个处理顺序来看,我们就应该知道,在信号处理之前,我们一定要有槽函数的这个定义,如果没有定义,我们就错过了这个信号的处理,自然而言的,女朋友的”蜀道难“也就来了。
那么我们回到Qt就知道,connect函数实际上是一个回调函数,信号是函数吧?槽是函数吧?那么这两个函数作为了connect函数的参数,也就成就了一个典型回调函数。
那么既然介绍到了connect,对于参数部分我们就不用提及了,对于C++中的库函数我们都是知道来源于谁的,那么connect函数是来源于谁呢?
牵扯到了这个问题,我们就不得不谈一谈Qt中的一个继承关系,拿隔壁java举例,我们知道java的所有类都继承于一个专门的类,叫做Object,在Qt中也有一个类似的设定,即QObject是所有内置类的祖宗:
那么connect函数呢就是QObject中的一个静态成员函数。
//connect to a functor, with a "context" object defining in which event loop is going to be executedtemplate <typename Func1, typename Func2>static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection)
这是它的一个函数定义。
对于我们之前看到的connect函数好像又有所不同,我们之前使用的connect函数好像没有那么复杂,我们之前使用Qt函数的原型是:
可是你看上面的类型,好像无论如何都没有办法和char*打上交道,对于第一个和第三个来说多正常,因为这两个参数是接收控件的嘛,子类赋值给基类,非常正常,可是其他参数呢?
之前使用第二个和第四个的参数可是函数指针类型,和char*是一点没有关系的,这怎么能够防在一起?实际上两个宏有关,一个是给槽函数传参的时候要搭配一个SLOT宏,一个是给信号函数传参的时候需要搭配一个SIGNAL宏。这两个宏可以让传入的指针变成char*。所以以前写的时候,是这样使用connect函数的:
connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&Widget::close));
但是这个写法是Qt4之前的了,对于新版的Qt就不用这样写了,实在是麻烦,新版的Qt5支持了一个重载版本,使得第二个和第四个参数变成了泛型指针,我们也就不用宏了,当然你要想那样写应该也没事儿~
这个时候的Qt就有了一个类型检查的功能,在上文提供的一个源码来说:
const typename QtPrivate::FunctionPointer<Func1>::Object *sender
这是一个类型萃取器,如果传入的参数第一个和第二个不匹配,第三个和第四个不匹配,主要指的是函数指针,编译就会报错了~当然,这里我们了解一下就行。
现在我们来了解一下信号,我们会发现之前使用button的信号的时候,有两个click,一个是过去分词形式,一个是动词形式:
其中这个锯齿形状的就是slot函数,也就是槽函数,比如我触发了一个信号,然后某个按钮就click了,对于波纹状的就是信号函数,是我们点击了,然后触发了信号。
这是二者的区别。
对于connect函数来说,第一个和第二个的参数类型应该是匹配的,第一个比如是button,第二个就应该是父类的信号,不能是其他的,比如QLineEdit的。
以上是对connect函数的一个简单理解。
两个问题
我咋知道QPushButton中有个clicked信号?我咋知道QWidget有个close槽?
也就是我们可以延展到我们怎么翻阅文档?
直接就是打开一手assistant,从中我们直接在索引部分找QPushButtion,但是我们似乎翻遍了文档也没有找到clicked信号。
这其实是因为clicked是继承于它的父类的,那么我们从哪里进到父类呢?
Inherits是继承,也就是说该类是继承于QAbstractButton的,下面的同理,我们点进去看看:
就可以看到它同样是继承了别的类的。
往下滑动就可以看到对应的槽函数和信号函数了,那么信号函数的缺省值我们不用管,稍微想想也能相通。
以上是对信号和槽的一个简单知识输出。
感谢阅读!