一、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语句进行处理的,这里只贴出一部分代码:

    1. bool QWidget::event(QEvent *event)
    2. {
    3. Q_D(QWidget);
    4. // ignore mouse events when disabled
    5. if (!isEnabled()) {
    6. switch(event->type()) {
    7. case QEvent::TabletPress:
    8. case QEvent::TabletRelease:
    9. case QEvent::TabletMove:
    10. case QEvent::MouseButtonPress:
    11. case QEvent::MouseButtonRelease:
    12. case QEvent::MouseButtonDblClick:
    13. case QEvent::MouseMove:
    14. case QEvent::TouchBegin:
    15. case QEvent::TouchUpdate:
    16. case QEvent::TouchEnd:
    17. case QEvent::ContextMenu:
    18. #ifndef QT_NO_WHEELEVENT
    19. case QEvent::Wheel:
    20. #endif
    21. return false;
    22. default:
    23. break;
    24. }
    25. }
    26. switch (event->type()) {
    27. case QEvent::MouseMove:
    28. mouseMoveEvent((QMouseEvent*)event);
    29. break;
    30. case QEvent::MouseButtonPress:
    31. // Don't reset input context here. Whether reset or not is
    32. // a responsibility of input method. reset() will be
    33. // called by mouseHandler() of input method if necessary
    34. // via mousePressEvent() of text widgets.
    35. #if 0
    36. resetInputContext();
    37. #endif
    38. mousePressEvent((QMouseEvent*)event);
    39. break;
    40. case QEvent::MouseButtonRelease:
    41. mouseReleaseEvent((QMouseEvent*)event);
    42. break;
    43. case QEvent::MouseButtonDblClick:
    44. mouseDoubleClickEvent((QMouseEvent*)event);
    45. break;
    46. #ifndef QT_NO_WHEELEVENT
    47. case QEvent::Wheel:
    48. wheelEvent((QWheelEvent*)event);
    49. break;
    50. #endif
    51. #ifndef QT_NO_TABLETEVENT
    52. case QEvent::TabletMove:
    53. case QEvent::TabletPress:
    54. case QEvent::TabletRelease:
    55. tabletEvent((QTabletEvent*)event);
    56. break;
    57. #endif

http://blog.csdn.net/chenlong12580/article/details/7720365

Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)的更多相关文章

  1. Qt中事件处理的顺序

    本站所有文章由本站和原作者保留一切权力,仅在保留本版权信息.原文链接.原文作者的情况下允许转载,转载请勿删改原文内容, 并不得用于商业用途. 谢谢合作.原文链接:Qt中事件处理的顺序 文章内容主要来自 ...

  2. CSS三栏布局的四种方法

    总括: 不管是三栏布局还是两栏布局都是我们在平时项目里经常使用的,也许你不知道什么事三栏布局什么是两栏布局但实际已经在用,或许你知道三栏布局的一种或两种方法,但实际操作中也只会依赖那某一种方法,本文具 ...

  3. CSS系列,三栏布局的四种方法

    三栏布局.两栏布局都是我们在平时项目里经常使用的,今天我们来玩一下三栏布局的四种写法,以及它的使用场景. 所谓三栏布局就是指页面分为左中右三部分然后对中间一部分做自适应的一种布局方式. 1.绝对定位法 ...

  4. jQuery 2.0.3 源码分析Sizzle引擎 - 编译函数(大篇幅)

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 从Sizzle1.8开始,这是Sizzle的分界线了,引入了编译函数机制 网上基本没有资料细说这个东东的,sizzle引入这 ...

  5. 51ak带你看MYSQL5.7源码1:main入口函数

    从事DBA工作多年 MYSQL源码也是头一次接触 尝试记录下自己看MYSQL5.7源码的历程 目录: 51ak带你看MYSQL5.7源码1:main入口函数 51ak带你看MYSQL5.7源码2:编译 ...

  6. Qt中printsupport的注意点和使用方法

    问题:Qt中包含QPrintDialog.QPrinter.QPrintPreviewDialog失败:在引入printsupport后报cpp:651: error: undefined refer ...

  7. jQuery源码分析-03扩展工具函数jQuery.extend

    // 扩展工具函数 jQuery.extend({ // http://www.w3school.com.cn/jquery/core_noconflict.asp // 释放$的 jQuery 控制 ...

  8. .17-浅析webpack源码之compile流程-入口函数run

    本节流程如图: 现在正式进入打包流程,起步方法为run: Compiler.prototype.run = (callback) => { const startTime = Date.now( ...

  9. 30s源码刨析系列之函数篇

    前言 由浅入深.逐个击破 30SecondsOfCode 中函数系列所有源码片段,带你领略源码之美. 本系列是对名库 30SecondsOfCode 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...

随机推荐

  1. mybatis和hibernate对比

    Hibernate是一个数据库表和java对象之间完全映射的框架,java开发人员直接对java对象操作,而不对数据库表进行操作: Mybatis是对SQL语句和java对象进行映射,仍需要开发人员编 ...

  2. c++ 10

    一.二叉树 1.基本特征 1)树型结构的最简模型,每个节点最多有两个子节点--左子节点和右子节点. 2)单根性,每个子节点有且仅有一个父节点,整棵树有且仅有一个根节点. 3)递归性,以任何一个节点为根 ...

  3. docker初步

    [Note,]由于docker的局限性,docker只能运行在64位的系统中 docker软件应用程序可以重复地运行在任何地方,因为它的容器包含了所有的环境依赖关系! docker有三种方式运行 作为 ...

  4. Top 15 Tools To Make Animated GIFs From Images & Video

    Creating an animated GIF picture from photos or video with Adobe Photoshop is easy, but not everyone ...

  5. 【SVN Working copy is too old (format 10, created by Subversion 1.6)】解决方式

    SVN同步或者提交的时候出现类似错误信息: The working copy needs to be upgraded svn: Working copy 'D:\adt-bundle-windows ...

  6. 使用ant自动编译、打包生成apk文件

    上次使用命令行生成apk文件<Android 命令行编译.打包生成apk文件>,学习命令行生成的目的是为了编写ant打下基础. 一. ant环境 下载ant包,配置环境变量 二.ant编译 ...

  7. Ubuntu包管理命令 dpkg、apt和aptitude

    起初GNU/Linux系统中仅仅有.tar.gz.用户 必须自己编译他们想使用的每个程序.在Debian出现之後,人们觉得有必要在系统 中加入一种机 制用来管理 安装在计算机上的软件包.人们将这套系统 ...

  8. Juqery 中使用 ajax

    从 test.js 载入 JSON 数据,附加参数,显示 JSON 数据中一个 name 字段数据. jQuery 代码: $.getJSON("test.js", { name: ...

  9. Firebase远程更新应用

    能打造出色的应用不意味着一定能在商业上取得成功,两者之间还有许多工作要做,绝不能简单发布应用后就宣告“收工”.您需要能迅速根据用户反馈作出调整.测试新功能,以及向用户提供他们最关注的内容. Fireb ...

  10. 21. DNS 配置和端口检测

    一.将本机的 DNS 配置为 8.8.8.8 ,用 nslookup (还可以使用 host.dig)验证 # 修改配置文件     # vim /etc/resolv.conf # 在文件的最后加入 ...