Qt的事件和与Widget跨线程交互

一般gui的程序的模型总有至少两个主要线程,一个是界面的主事件循环所在的线程,另一个是处理工作任务的线程,工作线程看不见,在后台处理事务产生数据,然后显示在界面上。例如一个即时通讯客户端,主界面显示好友列表,工作线程接受来自网络的消息,收到消息后,要通知界面,将对应的好友的头像闪烁显示。这就要跨线程

记得C#中有委托delegate,有InvokeRequired属性判断是否同线程操作,有Invoke来调用跨线程的委托。初学PySide,遇到同样的问题,看了半天文档,发现没有和C#类似的手段。但是,反倒可以用更有条理的方式来处理这样的跨线程调用请求,那就是事件。

QEvent是所有Qt事件的基类,构造函数只接受一个参数,那就是QEvent.Type类型的事件类型参数,如果是内置的事件类型,可以直接使用已定义的类型,例如QEvent.Close,它本质是一个int整数。如果要定义一个自己的事件,就需要一个这样的数字,而且和已有的所有事件类型不重复。

首先,使用QEvent.registerEventType这个静态方法来注册一个自己的类型,自定义的类型的值的返回是(QEvent.User, QEvent.UserMax)之间的一个数字,调用registerEventType时可以指定这样一个自己的数字,也可以不指定,由其自动分配一个数字。例如:

EVENT_INCOMING_MESSAGE = QEvent.registerEventType(QEvent.User + 0x01)

有了这个自己的类型,然后就是构建一个自己的事件类:

class IncomingMessageEvent(QEvent):
    def __init__(self, msg):
        super(IncomingMessageEvent, self).__init__(
            QEvent.Type(EVENT_INCOMING_MESSAGE)
        )
        self.msg = msg

那么如何在工作线程中将该事件“投递”至窗口?可以使用QCoreApplication的postEvent方法,注意不是sendEvent,是postEvent,他们的区别就在于postEvent能跨线程“投递”,因为sendEvent是直接将事件送至目标Widget来处理,并返回处理结果,而postEvent是将事件插入处理队列之后返回,并不等待至事件获得实际处理

假如app是主界面的一个QApplication对象,dlg是主界面的一个QDialog对象,msg是要投递的消息内容,那么将这个自己的事件投递至dlg的方法就是:

app.postEvent(dlg, IncomingMessageEvent(msg))

事件是投递完成,那么在QDialog中还得处理这个事件,不然dlg就要当SPAM来处理了... 

所有Qt的Widget处理事件,都是由它的event方法来进行,所以只需要在自己的Widget中实现一个自己的event方法,该方法接受单个QEvent类型的参数。

class MainFrame(QDialog):
    # ......
    def event(self, evt):
        if evt.type() == EVENT_INCOMING_MESSAGE:
            if hasattr(evt, 'msg'):
                msg = evt.msg
                self.show_incoming_message(msg) # 在界面显示该消息
        return super(MainFrame, self).event(evt)

这时就可以安全的处理要显示的内容了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值