Qt 的事件原理

Qt的事件比如那些特定事件 ,估计大家都会使用,但是各种原理未必所有人都能理解深透,现在上图

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

[cpp] view plain copy

  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
时间: 2024-10-09 23:29:08

Qt 的事件原理的相关文章

剖析Qt的事件机制原理

版权声明 请尊重原创作品.转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正. QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 QT源码解析(二)深入剖析QT元对象系统和信号槽机制 QT源码解析(三)深入剖析QT元对象系统和信号槽机制(续) QT源码解析(四)剖析Qt的事件机制原理 QT源码解析(五)QLibrary跨平台调用动态库的实现 QT源码解析(六)Qt信号槽机制与事件机制的联系 QT源码解析(七)Qt创建窗

Qt中事件分发源代码剖析(一共8个步骤,顺序非常清楚:全局的事件过滤器,再传递给目标对象的事件过滤器,最终传递给目标对象)

Qt中事件分发源代码剖析 Qt中事件传递顺序: 在一个应该程序中,会进入一个事件循环,接受系统产生的事件,并且进行分发,这些都是在exec中进行的.下面举例说明: 1)首先看看下面一段示例代码: [cpp] view plaincopy int main(int argc, char *argv[]) { QApplication a(argc, argv); MouseEvent w; w.show(); return a.exec(); } 2)a.exec进入事件循环,调用的是QAppli

Libevent的IO复用技术和定时事件原理

Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易读:跨平台,支持 Windows. Linux. *BSD 和 Mac Os:支持多种 I/O 多路复用技术, epoll. poll. dev/poll. select 和 kqueue 等:支持 I/O,定时器和信号等事件:注册事件优先级. 1 Libevent中的epoll Libevent重

Qt自定义事件实现及子线程向主线程传送事件消息

最近在重新学习Qt的时候,因为要涉及到子线程与主线程传递消息,所以便琢磨了一下,顺便把实用的记录下来,方便自己以后查询及各位同仁的参考! 特此声明,本篇博文主要讲述实用的,也就是直接说明怎么实现,就不打算陈述一大堆理论啦,不过,还是建议大家去查查相应的理论比较好,这样能对Qt的消息传送机制的理解更加深入! 根据网上大多数人的资料,要实现自定义消息,需要从QEvent 派生一个自定义的事件:其实也可以不需要,只要使用QEvent::Type自定义一个事件就行了.在这里,本人把两种实现方法都在这里讲

atitit 业务 触发器原理. 与事件原理 docx

atitit 业务 触发器原理. 与事件原理 docx 1.1. 呵呵,你需要需要一个业务 触发器..1 1.2. 触发器/事件/中断的原理1 1.3. Io 硬件中断的原理( 中断的低层有cpu轮询实现)1 1.4.  Ios事件的派发(Event Delivery)的过程 ,2 1.5. 事件的派发:2 1.1. 呵呵,你需要需要一个业务 触发器.. 个人建议使用数据库 触发器,  触发这个事件..不个变化的记录id记录下来,然后,使用一个轮询器, 然后把db触发器转换为程序代码事件.. 触

Android Touch事件原理加实例分析

Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. Android Touch事件原理描述 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP. 当屏幕中包含一个ViewGr

JS模拟键盘事件 -- 原理及小例子

小例子: (Chrome下可用,其他浏览器未测试,使用新方法,暂不考虑兼容性) 代码如下: 1 <input type="button" tabindex="-1" value="点点点点点" id="btn"> 2 <input type="text" placeholder="1"> 3 <input type="text" plac

Qt中事件分发源代码剖析

Qt中事件分发源代码剖析 Qt中事件传递顺序: 在一个应该程序中,会进入一个事件循环,接受系统产生的事件,并且进行分发,这些都是在exec中进行的. 下面举例说明: 1)首先看看下面一段示例代码: int main(int argc, char *argv[]) { QApplication a(argc, argv); MouseEvent w; w.show(); return a.exec(); } 2)a.exec进入事件循环,调用的是QApplication::exec(): int

Qt Focus事件,FocusInEvent()与FocusOutEvent()

描述:一开始我要实现的目的就是,在一个窗体上有多个可编辑控件(比如QLineEdit.QTextEdit等),当哪个控件获得焦点,哪个控件的背景就高亮用来起提示作用,查了下文档应该用focusInEvent()和focusOutEvent(), 在实际过程中,我犯了十分严重的错误,最开始的时候我是这样做的:我重写了窗体QWidget的这两个函数,然后再在函数体中把QFocusEvent事件传递给窗体上的QLineEdit控件: void Widget::focusInEvent(QFocusEv