Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)
一、Qt中事件处理的方式
1、事件处理模式一
首先是事件源产生事件,最后是事件处理器对这些事件进行处理。然而也许大家会问,
Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是每个事件都对应同一个事件处理器,在该事件处理器中对不同的事件进行分类处理,这样的弊端有两点:第一,导致该事件处理器过于臃肿复杂;第二,这样不便于扩展,当系统新增加事件类型或者是我们需要使用到自定义事件时,就不得不修改Qt的源码来达到目的。所以Qt设计者的做法是针对不同类型的事件提供不同的事件处理器与之对应。这里又有一个问题了,Qt中是怎么让不同类型事件与之对应的事件处理器相关联的呢?我们不难猜想在事件和事件处理器中间必定有一个桥梁。这个桥梁就是QObject::event()函数,该函数是虚函数,QObject的子类例如QWidget都实现了该函数。该函数的主要功能是进行事件的分发,也就是将不同类型的事件与之相对应的事件处理器相关联,该函数并不对事件进行处理,真正的事件处理是在事件处理器中进行的。
例如:当QWidget产生QPaintEvent事件后,QWidget的event函数会将该事件分发给QWidget::paintEvent()事件处理器,这样该事件就得到处理了。
以上内容用一个图形表示就是:
2、事件处理模式二
很多时候,我们只对某些特定的事件比较关心,例如:鼠标单击或者键盘按下等事件。其它的事件我们并不关心它是否发生,也无需对它们进行处理,这个时候最直接的想法就是将这些事件过滤掉,这样做既可以免去对它们进行处理,也可以避免它们对程序其它部分产生影响。因此,处理模式二中我们引入了事件过滤器这个概念。
如果对象安装了事件过滤器,则事件在到达目标对象之前先被事件过滤器截获,进行一些处理之后再交给目标对象,该模式总结为一个图如下:
注意:这里需要区别对待,如果你是使用installEventFilter()函数给目标对象注册事件过滤器,那么该事件过滤器只对该目标对象有效,只有该对象的事件需要先传递给eventFilter()函数进行过滤,然后调用相应的事件处理器进行处理,非目标对象则不受影响。如果你是给程序中唯一的QApplication对象注册事件过滤器,那么该过滤器对程序中的每一个对象都有效,任何对象的事件都是先传给eventFilter()函数,然后再使用事件处理器进行处理。
3、事件处理模式三
Qt调用QApplicaton来发送一个事件。所以我们可以重新实现QApplication中的notify()函数来获取事件并进行处理,而且使用该函数获取事件的时间要早于事件过滤器获取事件的时间。但是使用事件过滤器较为简便,因为我们可以有多个事件过滤器,但是只能有一个notify()函数。
用一个图来总结该模式就是:
二、Qt中事件处理的方法
从以上三个处理模式我们可以看出,这是一个不断完善的过程,从3个模式的讨论中我们不难找到可以进行事件处理的地方,而这几个地方就是我们在编写程序的时候可以控制事件处理的地方。
1、event()函数
首先是控制事件分发的event()函数,我们可以改写该函数,改变事件的分发方式,这样就可以改变事件处理的结果。
2、notify()函数
实现该函数可以截获事件,并对事件加以处理,但是该方法很少用,这里不做介绍。
3、事件过滤器
实现自己的事件过滤器就可以改变事件处理的方法和结果,这个方法比较常用。
4、事件处理器
事件处理的最后一步,也是最重要的一步就是事件处理器,因为它才是真正进行事件处理的地方,我们可以改写以有的事件处理器,以此改变已有事件的处理方法和处理结果,我们也可以定义自己的事件类型和相应的事件处理器。
注意:以上四种方法中最常用的是后两者:事件过滤器和事件处理器。
补充内容:
1、事件的传递
包括鼠标和键盘事件在内的很多事件都可以被传递。如果事件在到达目标对象之前没有被截获处理,或者已经传递给了它的目标对象但目标对象并没有进行处理,那么此时,目标对象的父对象将变成新的目标对象,整个事件处理的过程将重复进行,直到该事件被处理或者到达最顶层对象为止。
2、event实例解析
下面的代码是QWidget::event()函数的代码,从代码中可以看出event()函数确实只进行事件的分发而不负责事件的处理。由于函数代码过多,且都是一类型的用switch语句进行处理的,这里只贴出一部分代码:
- bool QWidget::event(QEvent *event)
- {
- Q_D(QWidget);
- // ignore mouse events when disabled
- if (!isEnabled()) {
- switch(event->type()) {
- case QEvent::TabletPress:
- case QEvent::TabletRelease:
- case QEvent::TabletMove:
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- case QEvent::MouseButtonDblClick:
- case QEvent::MouseMove:
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- case QEvent::ContextMenu:
- #ifndef QT_NO_WHEELEVENT
- case QEvent::Wheel:
- #endif
- return false;
- default:
- break;
- }
- }
- switch (event->type()) {
- case QEvent::MouseMove:
- mouseMoveEvent((QMouseEvent*)event);
- break;
- case QEvent::MouseButtonPress:
- // Don't reset input context here. Whether reset or not is
- // a responsibility of input method. reset() will be
- // called by mouseHandler() of input method if necessary
- // via mousePressEvent() of text widgets.
- #if 0
- resetInputContext();
- #endif
- mousePressEvent((QMouseEvent*)event);
- break;
- case QEvent::MouseButtonRelease:
- mouseReleaseEvent((QMouseEvent*)event);
- break;
- case QEvent::MouseButtonDblClick:
- mouseDoubleClickEvent((QMouseEvent*)event);
- break;
- #ifndef QT_NO_WHEELEVENT
- case QEvent::Wheel:
- wheelEvent((QWheelEvent*)event);
- break;
- #endif
- #ifndef QT_NO_TABLETEVENT
- case QEvent::TabletMove:
- case QEvent::TabletPress:
- case QEvent::TabletRelease:
- tabletEvent((QTabletEvent*)event);
- break;
- #endif
http://blog.csdn.net/chenlong12580/article/details/7720365
Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)的更多相关文章
- Qt中事件处理的顺序
本站所有文章由本站和原作者保留一切权力,仅在保留本版权信息.原文链接.原文作者的情况下允许转载,转载请勿删改原文内容, 并不得用于商业用途. 谢谢合作.原文链接:Qt中事件处理的顺序 文章内容主要来自 ...
- CSS三栏布局的四种方法
总括: 不管是三栏布局还是两栏布局都是我们在平时项目里经常使用的,也许你不知道什么事三栏布局什么是两栏布局但实际已经在用,或许你知道三栏布局的一种或两种方法,但实际操作中也只会依赖那某一种方法,本文具 ...
- CSS系列,三栏布局的四种方法
三栏布局.两栏布局都是我们在平时项目里经常使用的,今天我们来玩一下三栏布局的四种写法,以及它的使用场景. 所谓三栏布局就是指页面分为左中右三部分然后对中间一部分做自适应的一种布局方式. 1.绝对定位法 ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 编译函数(大篇幅)
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 从Sizzle1.8开始,这是Sizzle的分界线了,引入了编译函数机制 网上基本没有资料细说这个东东的,sizzle引入这 ...
- 51ak带你看MYSQL5.7源码1:main入口函数
从事DBA工作多年 MYSQL源码也是头一次接触 尝试记录下自己看MYSQL5.7源码的历程 目录: 51ak带你看MYSQL5.7源码1:main入口函数 51ak带你看MYSQL5.7源码2:编译 ...
- Qt中printsupport的注意点和使用方法
问题:Qt中包含QPrintDialog.QPrinter.QPrintPreviewDialog失败:在引入printsupport后报cpp:651: error: undefined refer ...
- jQuery源码分析-03扩展工具函数jQuery.extend
// 扩展工具函数 jQuery.extend({ // http://www.w3school.com.cn/jquery/core_noconflict.asp // 释放$的 jQuery 控制 ...
- .17-浅析webpack源码之compile流程-入口函数run
本节流程如图: 现在正式进入打包流程,起步方法为run: Compiler.prototype.run = (callback) => { const startTime = Date.now( ...
- 30s源码刨析系列之函数篇
前言 由浅入深.逐个击破 30SecondsOfCode 中函数系列所有源码片段,带你领略源码之美. 本系列是对名库 30SecondsOfCode 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...
随机推荐
- nRF51822 SDK初体验
作为两家BLE芯片大厂之一,nordic不像TI那么开放,nordic的开发资料是很难找的. 今天有幸得到nordic的BLE芯片nRF51822的SDK,看了一下. 首先,nordic号称协议栈 ...
- keil c51中C程序的启动过程
汇编是从org 0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接.下面看看它和main()函数是 ...
- bitmap 内存溢出OOM的解决办法分享
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...
- Thread详解
具体可参考:Java并发编程:Thread类的使用,这里对线程状态的转换及主要函数做一下补充. 一.线程状态转换图 注意: 阻塞状态是线程阻塞在synchronized代码块时的状态,而阻塞在Lock ...
- 关于java.sql.SQLRecoverableException: Closed Connection异常的解决方案(转)
在项目中碰到了一个应用异常,从表象来看应用僵死.查看Weblogic状态为Running,内存无溢出,但是出现多次线程堵塞.查看Weblogic日志,发现程序出现多次Time Out. 我们知道,We ...
- bzoj1752 [Usaco2005 qua]Til the Cows Come Home
Description Bessie is out in the field and wants to get back to the barn to get as much sleep as pos ...
- 杭电2059(dp)
龟兔赛跑 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- SimHash算法
短文本合并重复(去重)的简单有效做法 - 旁观者 - 博客园 短文本合并重复(去重)的简单有效做法 SimHash算法 - ACdreamer - 博客频道 - CSDN.NET SimHash算法
- Direct3D 索引缓存
小学的时候我们知道3个顶点组成一个三角形,那么四个顶点我们会说有4个三角形.这就是一个顶点同时参与了四次绘制三角形的结果. 在程序中也一样,比如我们绘制的两个三角形是挨着一起的,总有几个顶点是重合的. ...
- pyqt说明
我是个PHP程序员,不过有时候觉得需要写些小软件,对于我这种不太熟悉桌面软件开发的人来说,界面问题最让我头痛.听说Qt很强大,而且是跨平台,所以决定学习它用来弥补我写桌面软件的不足. Qt一般是通过C ...