
示例实现
在这里我们使用Qt Creator自动生成的槽函数,不用写信号与槽函数的映射。(Qt Creator自动生成槽函数的方法:右击控件→Go to slot,选择槽函数所要对应的信号函数,确定后就会生成槽函数的声明和定义框架。)
右击控件radioButton,选中“Go to slot”选项,在信号窗口中选择信号,如图3-14所示。在本示例中我们用到的是clicked()信号,确定后就会跳转到槽函数的定义框架中,槽函数的声明已经自动生成,这一点和Winform差不多。然后只需要填充槽函数即可。
你用QT designer,这个只是一个专门做Ui的工具,不能添加代码的。要用Qt Creator才行,在控件上单击右键,有个go to slots选项,点击后鼠标自动移动到代码里面,很方便!
接上一章链接部分,继续讲信号槽是如何调用的
首先看看信号是如何触发的,一般都是这么写:
emit sendertest_Signal(1);
这个emit是啥,其实啥也不是,就是一个空的define
它只是用来标记这是一个信号方便阅读,其实这个信号本身也是一个函数,只不过我们没有实现,这是语言的基础,定义了函数肯定是要实现的,那么它的实现在哪呢,答案还在moc文件内部,以之前的例子为例,它的实现是这样的
在这里将信号的参数包装成了void的数组,然后调用元对象的activate函数,如下
这一部分主要是判断信号是否有链接槽函数
之前讲过Qt4的槽函数是存储在Connection的callFunction对象,如果这个不为空就会判断为Qt4的链接方式
这种就比较简单,直接调用callFunction即可,这个callFunction是什么呢,不知道是否还记得,之前链接的时候讲过,它就是moc文件里的qt_static_metacall,如果不记得了回去看看,这里在放出
是否还记得Qt5的槽放在哪呢,它放在一个QSlotObject对象里,Connection保存的是这个对象的地址,因此通过判断这个地址是否为空就能判断是否为Qt5的调用方式
还记得之前将的QSlotObject吗,它是QSlotObjectBase的子类,为了方便再贴出来看看
这里面调用的又是 FuncType(也就是FunctionPointer<Func>)的call函数,好记得它是什么吗,就是用来判断槽函数是否为receiver成员函数的那个模板类,再贴出来看看
到此就会调用到我们的槽函数,Qt5方式的调用也就结束了
Qt信号槽在链接的时候最后一个参数代表的是链接方式,包括5中
一般用的比较多的就是AutoConnection和QueuedConnection,如果是auto的方式,调用时会判断信号所在线程和槽所在线程是否是一个线程,如果不是就是queue的方式调用,具体是这样判断的
如果是QueuedConnection,会把当前的信号包装成一个QMeCallEvent的事件,进入到事件循环来调用槽函数
2、用了QueuedConnection是不是就代表是异步了呢?
那么事件循环是怎么调用到这个函数的呢?
有时我们展示了一个列表, 并想提供查看某项列表的详细内容, 我们会在列表项的末端加一个查看按钮, 这时我们如何在按按钮的时候得知这是那一项呢 这时就需要带参数的信号, 信号是可以带参数的, 参数会在信号发送时携带, 并传递给接收此信号的槽
from PyQt4 import QtGui, QtCore
class MyButton(QtGuiQPushButton):
myclicked = QtCorepyqtSignal(int)
def __init__(self, _id, args, kwargs):
QtGuiQPushButton__init__(self, args, kwargs)
self_id = _id
selfconnect(self, QtCoreSIGNAL("clicked()"), selfemitMyclicked)
def emitMyclicked(self):
selfmyclickedemit(self_id)
app = QtGuiQApplication([])
w = QtGuiQWidget()
wresize(100, 100)
def showMsg(_id):
QtGuiQMessageBoxinformation(w, u"信息", u"查看 %d" % _id)
btn = MyButton(1, u"查看1", w)
wconnect(btn, QtCoreSIGNAL("myclicked(int)"), showMsg)
btn2 = MyButton(2, u"查看2", w)
btn2move(0, 30)
wconnect(btn2, QtCoreSIGNAL("myclicked(int)"), showMsg)
wshow()
appexec_()
上面例子可以看出, QObjectemit 发送带参数的信号时要携带参数 当然上面例子也可以用下面方式来写
from PyQt4 import QtGui, QtCore
class MyButton(QtGuiQPushButton):
def __init__(self, _id, args, kwargs):
self_id = _id
QtGuiQPushButton__init__(self, args, kwargs)
selfconnect(self, QtCoreSIGNAL("clicked()"), selfemitClicked)
def emitClicked(self):
selfemit(QtCoreSIGNAL("myclicked(int)"), self_id)
app = QtGuiQApplication([])
w = QtGuiQWidget()
wresize(100, 100)
def showMsg(_id):
QtGuiQMessageBoxinformation(w, u"信息", u"查看 %d" % _id)
btn = MyButton(1, u"查看1", w)
wconnect(btn, QtCoreSIGNAL("myclicked(int)"), showMsg)
btn2 = MyButton(2, u"查看2", w)
btn2move(0, 30)
wconnect(btn2, QtCoreSIGNAL("myclicked(int)"), showMsg)
wshow()
appexec_()
进程肯定不会产生了。Qt的信号槽是个很复杂的机制,哥大致给你介绍一下Qt的信号槽既可以同步触发,也可以异步触发。当你进行connect的时候,实际上还有第五个参数(可以自己看SDK的介绍)。如果说是默认的,那么要看信号和槽是否属于同一个线程(这里,你可以简单理解为是否是同一个类),然后根据connect的第五个属性来判断是否是同步还是异步。比如BlockingQueuedConnection模式,就会出现你说的多次触发信号阻塞问题,他只有等到上一个触发完成才能继续。槽函数不会产生新线程,他是决定了槽函数声明在哪个线程中,如果默认情况下,在同一个线程里面是同步的,你此时可以理解为普通调用,如果在不同线程里面,槽函数运行的线程通常是异步调用,但是还有一个所谓的事件中心一直run着在处理,就是一个信号队列,没触发一个信号就入队列,先进先出。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)