Inside Qt Series (十六):Event Overview

Inside Qt Series (十六):Event Overview

 

作者:Q-Kevin @ http://www.qkevin.com

Qt 的应用程序都是事件驱动的,以前我一直都很好奇,事件驱动到底是如何工作的?好在Qt是开放源代码的,让我得以有机会从Qt的源代码中学习到一个事件驱动的体系结构是什么样子的。

在Qt中,所有的Event对象都是由从QEvent类派生出来的类来描述的。通过调用QObject::event()函数来发送到从QObject继承出来的Qt对象,这个对象会有相应的方法来处理这个事件。

事件的来源主要有两种

1, 系统产生的
通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等, 放入系统的消息队列中. Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.

2, Qt应用程序程序自身产生的
程序产生事件有两种方式, 一种是调用QApplication::postEvent(). 例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理. 另一种方式是调用sendEvent()函数. 这时候事件不会放入队列, 而是直接被派发和处理, QWidget::repaint()函数用的就是这种方式.

但是对于Qt来说,它并不需要区分这些事件的来源,他们都会采用同样的方式来一致的处理。而且几乎每一种事件都会有一个特定的类相对应。如:QMouseEvent对应鼠标事件,QKeyEvent对应键盘就十分,QCloseEvent对应窗口关闭事件,等等。

 

QtEvent 的类型很多, 常见的 event类型如下:

** 键盘事件: 按键按下(press)和松开(release)
** 鼠标事件:鼠标按键的按下(press)和松开(release),鼠标移动(move),双击(double click)
** 拖放事件: 用鼠标进行拖放(drag and drop)
** 滚轮事件: 鼠标滚轮滚动(wheel event)
** 绘屏事件: 重绘屏幕的某些部分(paint)
** 定时事件: 定时器到时(timer)
** 焦点事件: 键盘焦点移动(focus)
** 进入和离开事件: 鼠标移入widget之内,或是移出(focus in & focus out)
** 大小改变事件: widget的大小改变(resize)
** 显示和隐藏事件: widget显示和隐藏(show & hide)
** 窗口事件: 窗口是否为当前窗口
** 还有一些不太常见的event,比如socket事件,剪贴板事件,字体改变,布局改变等

在大多数情况下,Qt类都是通过一个虚函数来实现对事件的响应的,这样对于继承出来的类来说,就有机会重新实现这个事件的响应方法。比如,我们会经常写QWidget::paintEvent(…)函数来对一个widget做paint处理,其实,这就是在响应一个QPaintEvent事件。

事件发送的方法主要有两种:

1, send event:
这可以通过调用QCoreApplication::sendEvent(QObject* receiver, QEvent* event)这个函数来实现。当通过这个函数调用来发送一个事件的时候,事件响应函数立刻就会被调用到,也就是说,这是一个同步调用。

2, post event:
这可以通过调用QCoreApplication::postEvent(QObject* receiver, QEvent* event)这个函数来实现。当通过这个函数调用来发送一个事件的事件,事件响应函数并没有立刻被调用,而是把事件先放到一个事件队列里面去,然后在Qt的Event Loop下次才会检索到这个event,然后调用相应的事件处理函数。
Qt的event loop还有这样一个特性,他会把相同的event进行合并,以避免这些事件被执行多次。如:你一次post了多个QPaintEvent事件,那么Qt会把这些事件合并成为一个QPaintEvent事件,这样做的好处是节约系统资源,只paint一次就可以了,而且还有效的避免的界面的闪烁。

Qt有以下几种不同的事件处理方法:

1, Qt的类已经实现的那些事件处理方法,如:paintEvent(..), mousePressEvent(..), keyPressEvent(..), 等等。这些事件处理函数都是虚函数,我们可以在自己定义的类里面重新实现这些函数来处理相应的事件。这是最经常实用,这是最通用,最容易的方法。

2, 重新实现QCoreApplication::notify(QObject* receiver, QEvent* event)函数。这也是一个非常强大,而且可以对事件进行完全控制的方法。但是在一个应用程序中,只能有一个QCoreApplication类(或者是它的子类)的实例存在。

3, 在QCoreApplication(或者其子类)的实例上面安装event filter来处理事件。这样的event filter可以处理到所有的widget event,所有它和重写QCoreApplication::notify函数功能一样强大。另外,在一个应用程序中可以有多个全局性的event filter。需要注意的是,application的event filter只有在那些在主线程中的对象调用。

4, 重新实现QObject::event函数。在这个函数中,你能获得更多的事件控制权限,它会在一个对象的特定事件处理函数之前被调用。比如说:paintEvent, keyPressEvent,等等。

5, 给一个对象安装一个event filter,这个filter将会获得这个对象的所有事件调用。

事件运行机制

有两种event调度方式,一种是同步的, 一种是异步.

** 当应用程序的main函数调用QCoreApplication的exec()方法是,应用程序进入Qt的主事件循环,它从事件队列中取出本窗口及系统事件,然后把他们打包成相应的QEvent的子类对象,并且使用函数QCoreApplication::notify函数发送事件到相应的QObject对象。在这个主事件循环中,是异步处理的。

** QApplication::sendEvent()的时候, 消息会立即被处理,是同步的. 实际上QApplication::sendEvent()是通过调用QApplication::notify(), 直接进入了事件的派发和处理环节
 

Event Filter:

一个event filter是一个能够接收所有发送到这个对象上面的事件的对象,并且能够停止或者转发到这个对象上的事件。它通过eventFilter()函数来接收事件,如果这个事件应该被过滤掉(如停止这个事件,或者这个事件已经被处理了,下面不再需要了),那么eventFilter函数返回true,如果不应该被过滤掉,就返回false。

QObject还提供了event filter的安装和卸载方法,如下所示:

a) QObject::installEventFilter(const QObject* filterObject)

b) QObject::removeEventFilter(QObject* filterObject)
 

 
======================================================================
声明:
《Inside Qt Series》专栏文章是(http://www.qkevin.com)原创技术文章。
本系列专栏文章可随意转载,但必须保留本段声明和每一篇文章的原始地址。
作者保留版权,未经作者同意,不得用于任何商业用途

《Inside Qt Series》专栏文章总索引: http://www.qkevin.com/qt
本文原始地址:http://www.qkevin.com/archives/146

前一篇:Qt/e 输入法,How it works?, http://www.qkevin.com/archives/106
后一篇:Writing ,,,,,,,  http://www.qkevin.com/qt
====================================================================

CSDN海神之光上传的代码均可运行,亲测可用,直接替换数据即可,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b或2023b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主或扫描博客文章底部QQ名片; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪(CEEMDAN)、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 1. EMD(经验模态分解,Empirical Mode Decomposition) 2. TVF-EMD(时变滤波的经验模态分解,Time-Varying Filtered Empirical Mode Decomposition) 3. EEMD(集成经验模态分解,Ensemble Empirical Mode Decomposition) 4. VMD(变分模态分解,Variational Mode Decomposition) 5. CEEMDAN(完全自适应噪声集合经验模态分解,Complementary Ensemble Empirical Mode Decomposition with Adaptive Noise) 6. LMD(局部均值分解,Local Mean Decomposition) 7. RLMD(鲁棒局部均值分解, Robust Local Mean Decomposition) 8. ITD(固有时间尺度分解,Intrinsic Time Decomposition) 9. SVMD(逐次变分模态分解,Sequential Variational Mode Decomposition) 10. ICEEMDAN(改进的完全自适应噪声集合经验模态分解,Improved Complementary Ensemble Empirical Mode Decomposition with Adaptive Noise) 11. FMD(特征模式分解,Feature Mode Decomposition) 12. REMD(鲁棒经验模态分解,Robust Empirical Mode Decomposition) 13. SGMD(辛几何模态分解,Spectral-Grouping-based Mode Decomposition) 14. RLMD(鲁棒局部均值分解,Robust Intrinsic Time Decomposition) 15. ESMD(极点对称模态分解, extreme-point symmetric mode decomposition) 16. CEEMD(互补集合经验模态分解,Complementary Ensemble Empirical Mode Decomposition) 17. SSA(奇异谱分析,Singular Spectrum Analysis) 18. SWD(群分解,Swarm Decomposition) 19. RPSEMD(再生相移正弦辅助经验模态分解,Regenerated Phase-shifted Sinusoids assisted Empirical Mode Decomposition) 20. EWT(经验小波变换,Empirical Wavelet Transform) 21. DWT(离散小波变换,Discraete wavelet transform) 22. TDD(时域分解,Time Domain Decomposition) 23. MODWT(最大重叠离散小波变换,Maximal Overlap Discrete Wavelet Transform) 24. MEMD(多元经验模态分解,Multivariate Empirical Mode Decomposition) 25. MVMD(多元变分模态分解,Multivariate Variational Mode Decomposition)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值