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 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...
随机推荐
- 转:helloworld:一个完整的WCF案例
原文地址:http://blog.csdn.net/mane_yao/article/details/5852845 WCF的ABC: A代表Address-where(对象在哪里)B代表Bindin ...
- 打印log 保存log
using UnityEngine; using System.Collections; using System.IO; using System; using System.Text; names ...
- java多态的理解----部分非原创
所谓多态,其实就是对于同一件事情,不同的对象要采取不同的行为,或者同一个对象在不同的情况下需要采取不同的行为方式. 不同的对象要采取不同的行为: 这有两种实现方式:接口实现和子类重新父类方法.这两种实 ...
- Swift——(一)为Swift内置类型加入属性
在看苹果官方的Swift Language的时候,遇到实验:Write an extension for the Double type that add an absoluteValue prope ...
- Git 推送分支
1.推送本地分支到远程: git push origin master 推送本地分支 master 到 远程的 origin 上面 git push origin test 将本地分支test推 ...
- NET基础课--Linq第三讲
LINQ 1.查询操作符 (1)源起 .net的设计者在IEnumerable<T>等接口基础之上定义了一系列的扩展方法来方便用户操作集合对象,这些扩展方法构成了LINQ的查询操作符 (2 ...
- android——仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中
转载请注明出处: www.cnblogs.com/shoneworn 我这里只是简单的用了两个listview来实现的,先上效果图.比较粗糙.预留了自定义的空间. 思路: 从上图应该可以看的出来.就是 ...
- ToggleButton --------- 按钮实现开关效果
ToggleButton(开关按钮)是Android系统中比较简单的一个组件,是一个具有选中和未选择状态双状态的按钮,并且需要为不同的状态设置不同的显示文本 ,默认状态下 关. ToggleButto ...
- oracle安装、配置、卸载、错误解决
oracle安装卸载的帖子很多,这里整理出一份,都只是给出一个链接,忘了时可以自己看看.哈哈,其实我也觉得已经不会忘了,被这个鸡毛问题困了两天,修改控制文件.环境变量.注册表什么的都不能解决问题,最后 ...
- long类型在C#和C++中的异同
C++中long是32位的整数类型. 而在C#中long是64位的,对应包装类型是Int64,int对应Int32. 显然C++中的long类型,而应该对应C#中的int, C#调用C++ ...