Qt 学习之路 2(23):自定义事件_亭台六七座的博客-程序员宅基地

技术标签: Qt 学习之路  Qt事件过滤器  QEvent  Qt自定义事件  Qt入门  Qt-学习之路  

尽管 Qt 已经提供了很多事件,但对于更加千变万化的需求来说,有限的事件都是不够的。例如,我要支持一种新的设备,这个设备提供一种崭新的交互方式,那么,这种事件如何处理呢?所以,允许创建自己的事件 类型也就势在必行。即便是不说那种非常极端的例子,在多线程的程序中,自定义事件也是尤其有用。当然,事件也并不是局限在多线程中,它可以用在单线程的程序中,作为一种对象间通讯的机制。那么,为什么我需要使用事件,而不是信号槽呢?主要原因是,事件的分发既可以是同步的,又可以是异步的,而函数的调用或者说是槽的回调总是同步的。事件的另外一个好处是,它可以使用过滤器。

Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展。在 Qt 中,你需要继承的类是QEvent

继承QEvent类,最重要的是提供一个QEvent::Type类型的参数,作为自定义事件的类型值。回忆一下,这个 type 是我们在处理事件时用于识别事件类型的代号。比如在event()函数中,我们使用QEvent::type()获得这个事件类型,然后与我们定义的实际类型对比。

QEvent::TypeQEvent定义的一个枚举。因此,我们可以传递一个 int 值。但是需要注意的是,我们的自定义事件类型不能和已经存在的 type 值重复,否则会有不可预料的错误发生。因为系统会将你新增加的事件当做系统事件进行派发和调用。在 Qt 中,系统保留 0 – 999 的值,也就是说,你的事件 type 要大于 999。这种数值当然非常难记,所以 Qt 定义了两个边界值:QEvent::UserQEvent::MaxUser。我们的自定义事件的 type 应该在这两个值的范围之间。其中,QEvent::User的值是 1000,QEvent::MaxUser的值是 65535。从这里知道,我们最多可以定义 64536 个事件。通过这两个枚举值,我们可以保证我们自己的事件类型不会覆盖系统定义的事件类型。但是,这样并不能保证自定义事件相互之间不会被覆盖。为了解决这个问题,Qt 提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名如下:

这个函数是 static 的,因此可以使用QEvent类直接调用。函数接受一个 int 值,其默认值是 -1;函数返回值是向系统注册的新的 Type 类型的值。如果 hint 是合法的,也就是说这个 hint 不会发生任何覆盖(系统的以及其它自定义事件的),则会直接返回这个值;否则,系统会自动分配一个合法值并返回。因此,使用这个函数即可完成 type 值的指定。这个函数是线程安全的,不必另外添加同步。

我们可以在QEvent子类中添加自己的事件所需要的数据,然后进行事件的发送。Qt 中提供了两种事件发送方式:


  1. 直接将event事件发送给receiver接受者,使用的是QCoreApplication::notify()函数。函数返回值就是事件处理函数的返回值。在事件被发送的时候,event对象并不会被销毁。通常我们会在栈上创建event对象,例如:

  2. event事件及其接受者receiver一同追加到事件队列中,函数立即返回。

    因为 post 事件队列会持有事件对象,并且在其 post 的时候将其 delete 掉,因此,我们必须在堆上创建event对象。当对象被发送之后,再试图访问event对象就会出现问题(因为 post 之后,event对象就会被 delete)。

    当控制权返回到主线程循环时,保存在事件队列中的所有事件都通过notify()函数发送出去。

    事件会根据 post 的顺序进行处理。如果你想要改变事件的处理顺序,可以考虑为其指定一个优先级。默认的优先级是Qt::NormalEventPriority

    这个函数是线程安全的。

    Qt 还提供了一个函数:

    这个函数的作用是,将事件队列中的接受者为receiver,事件类似为 event_type 的所有事件立即发送给 receiver 进行处理。需要注意的是,来自窗口系统的事件并不由这个函数进行处理,而是processEvent()。详细信息请参考 Qt API 手册。

现在,我们已经能够自定义事件对象,已经能够将事件发送出去,还剩下最后一步:处理自定义事件。处理自定义事件,同前面我们讲解的那些处理方法没有什么区别。我们可以重写QObject::customEvent()函数,该函数接收一个QEvent对象作为参数:

我们可以通过转换 event 对象类型来判断不同的事件:

当然,我们也可以在event()函数中直接处理:

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lmhuanying1012/article/details/78081625

智能推荐

position:fixed,如何水平垂直居中_meichaoWen的博客-程序员宅基地_fixed垂直水平居中

情况1、宽度确定(高度同理) width:8rem; height:8rem; position:fixed; left:0; right:0; margin:0 auto;情况2、宽度不确定 position:fixed;3 left:50%;4 top:50%;5 transform:translate(-5...

vue中methods、watch、computed之间的差别对比以及适用场景_dengnuo1980的博客-程序员宅基地

首先要说,methods,watch和computed都是以函数为基础的,但各自却都不同;一、computer当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性。<p id="app"> {{fullName}} </p><script> var vm = new Vue({ e...

Android Google原生系统刷机_mazaiting的博客-程序员宅基地

备份工具钛备份下载ROM的网站:魔趣androidfilehostlineageGoogle原生系统androidsage第三方 RECorangefoxTWRP原生跳过谷歌向导安装步骤TWRPI. 下载第三方 Recovery,如果想要刷非本机系统,则需要刷入该工具。选择对应手机型号及手机版本,并下载II. Official TWR...

马哥zabbix_骏马传奇的博客-程序员宅基地

zabbix架构中的组件 zabbix-server:C语言 OS:zabbix-agent zabbix-web:GUI,用于实现zabbix设定和展示 zabbix-proxy:分布式监控环境中的专用组件 zabbix-database:mysql,PGSQL(postgreSQL) ,oRACLE,db2,SQLit...

vlc_entry__main和vlc_entry__live555_c_m_deng的博客-程序员宅基地

由于vlc使用了大量的宏定义,为了便于分析源代码,我们首先将一些重要的源文件进行预编译,从而查看一些重要函数的定义。1. vlc_entry__live555(vlc-android0.0.5)1.1).预编译方法对vlc/modules/demux/makefile.in文件进行了修改,找到编译目标liblive555_plugin_la-live555.lo: live555.

vant实现下拉刷新和上拉加载_移动端:vant-list 实现下拉刷新,上拉加载功能_weixin_39684967的博客-程序员宅基地

常见问题List 的运行机制是什么?List 会监听浏览器的滚动事件并计算列表的位置,当列表底部与可视区域的距离小于offset时,List 会触发一次 load 事件。为什么 List 初始化后会立即触发 load 事件?List 初始化后会触发一次 load 事件,用于加载第一屏的数据,这个特性可以通过immediate-check属性关闭。为什么会连续触发 load 事件?如果一次请求加载的...

随便推点

iphone相册怎么加密_拍照成瘾照片多又乱?6款手机相册管理APP,让你省时省空间留下心中最爱..._weixin_39624367的博客-程序员宅基地

随着照片越拍越多,手机存储空间就会被占用更多,需要经常整理删除和上传到云空间保存。因此,我们不但要会拍,还要更会整理,把最美好的记忆存留在手机里。除了iPhone自带的相册(可以简单修图、批量删除和收藏)外,我还推荐以下APP给你。1 时光相册关键词:照片管理、自动备份、超大云空间点评:AI智能整理功能,自动识别照片中的人物、事物、地点,甚至是照片中的文字也能识别。超大云存储空间,一键备份海量照片...

DSP 连不上 JTAG, 'SC_ERR_PATH_BROKEN', 关注EMU1 EMU0_不纯洁的锌的博客-程序员宅基地

早先设计28335的板子,有EMU0 EMU1两线和DSP上两个引脚对应。这次做28069的原理图时,看到没有这两个对应引脚,网上查了一下EMU0 EMU1似乎也没什么用途,于是就把2条线省去。板子焊出来后,发现JTAG连不上芯片。报错如下:/*********************************************************************分割线

关于String 类的创建个数_apgywva897901的博客-程序员宅基地

(二)到底创建了几个 String 对象?关键字: java 面试题 string 创建几个对象作者:臧圩人(zangweiren) 发布时间:2008-06-30网址:http://zangweiren.javaeye.com>>>转载请注明出处!<<<我们首先来看一段代码:Java 代码 :String str=new String("abc");...

M1卡的块值的加、减、重储操作_喜欢做我自己的博客-程序员宅基地

M1卡的存储结构是按块来进行存储,一般分64块(S50卡),每四个块组成一个扇区,每隔扇区的结构图如下:一般的块是用来存取数据的,但是还有一些特殊的用途,比如钱包功能,这种情况下就需要对块的数据进行特殊处理,以严谨的数据来确保钱包的安全钱包值有四个字节大小,但是其按照小端存储的方式,即低字节在前,高字节在后。比如钱包是1000,转换成16进制是0x000003E8,块里面存储的0到3字节数据为E8 03 00 00,。钱包值取反为17FCFFFF。地址是指该块的块地址号。举例:E80300

Dynamics 365 CE Update消息PostOperation阶段Image的尝试_weixin_30666753的博客-程序员宅基地

我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面的微软最有价值专家(Microsoft MVP),欢迎关注我的微信公众号 MSFTDynamics365erLuoYong ,回复355或者20190827可方便获取本文,同时可以在第一间得...

线性判别分析(LDA)基本原理及实现_ruthy-wei的博客-程序员宅基地_线性判别分析

前言在主成分分析(PCA)原理总结(机器学习(27)【降维】之主成分分析(PCA)详解)中对降维算法PCA做了总结。这里就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 简称LDA)做一个总结。LDA在模式识别领域(比如人脸识别,舰艇识别等图形图像识别领域)中有非常广泛的应用,因此我们有必要了解下它的算法原理。在学习LDA之前,有必要将其自然语...

推荐文章

热门文章

相关标签