Qt的事件机制

事件过滤器:
  可以让一个对象侦听拦截另外一个对象的事件。
  实现原理:
  在所有Qt对象的基类:QObject中有一个
  类型为:QObjectList
  名字为:eventFilters
  的成员变量,当A给B安装了事件过滤器后
  B的eventList中就会保存A对象的指针,
  在B处理事件之前,会先检查eventList是
  否为空,如果不为空,就会调用事件过滤器函数eventFilter(),如果eventFilter()返回true,表示事件已经被处理完毕,Qt将直接返回进行下一事件处理,如果为false,事件将接着被送往剩下的事件过滤器或者是目标对象进行处理。

按照事件的起源将事件分为三类:

  Spontaneous事件-----自发事件

  由窗口系统产生,被放到系统队列中,通过事件循环逐个处理。

  Posted事件

  由Qt或是应用程序产生,被Qt组成队列,再通过事件循环处理。

  sent事件

  由Qt或是应用程序产生,但他们被直接发送到目标对象。

Qt事件循环的过程

  在调用QApplication::exec()时,程序进入了Qt的事件循环,

  事件循环的大致示意

 while (!exit_was_called)
{
while(!posted_event_queue_is_empty)
{
process_next_posted_event();
}
while(!spontaneous_event_queue_is_empty)
{
process_next_spontaneous_event();
}
while(!posted_event_queue_is_empty)
{
process_next_posted_event();
}
}

  可以看出,程序首先处理所有的posted事件,知道队列空,再处理Spontaneous事件,再处理因Spontaneous事件产生的posted事件。

  send事件不在事件循环内,因为他们不进入事件队列而是直接发送给目标对象

实例paint()事件:

  当一个widget第一次可见,或者是被遮挡后可见,窗口产生一个(Spontaneous)paint事件,要求程序重绘widget,事件循环最宗从事件队列中拣选这个事件并把他们分发到那个徐奥重画的widget对象。

  并不是所有paint事件都是窗口系统产生,当你调用update()去强行重画widget,这个widget会post一个paint事件给自己,这个paint事件被放入队列,最终被事件循环分发。

  而当你等不及事件循环时,本来应该调用paintEvent()强制立即重画,但是实际上不可行因为paintEvent()是受保护的函数,因此Qt提供了一个机制直接sending事件给对象,repaint()就使用了这个机制来进行立即重画。(这是update()更新和repaint()更新的区别)。

  posting相对于sending的一个优势就是给了Qt一个压缩事件的机会,假如在一个widget上连续调用update()十次,因update()而产生的这十个事件,会被自动地合并成一个单独的事件,

人工合成的事件

  Qt应用程序可以产生他们自己的事件,或是预定义类型,或是自定义类型。这可以通过创建QEvent类或它的子类的实例,并且调用QApplication::postEvent()或QApplication::sendEvent()来实现。

  这两个函数需要一个QObject* 与一个QEvent作为参数,如果使用postEvent(),要使用new操作符来创建事件对象,如

  QApplication::postEvent(mainWin,new QKeyEvent(QEvent::KeyPress,Key_X,'X',0));

如果使用sendEvent(),应该使用栈来创建事件

  QKeyEvent event(QEvent::KeyPress,Key_X,'X',0);

  QApplication::sendEvent(mainWin,&event);

定制事件类型

  Qt允许创建自己的事件类型,可以作为对象间的一种通讯机制。是因为这个可以是异步的,函数调用或槽调用总是同步的。另一个好处是可以被过滤

  post一个定制事件:

    const QEvent::Type MyEvent = (QEvent::Type)1234;

    ...

    QApplication::postEvent(obj,new QCustomEvent(MyEvent));

  事件必须是QCustomEvent类型(或子类)的。构造函数的参数是事件的类型,

  为了处理定制事件类型,要重新实现customEvent()函数:

  void MyLineEdit::customEvent(QCustomEvent *event)

  {

    if(event->type() == MyEvent){

      myEvent();

    }else{

      QLineEdit::customEvent(event);

    }

  }

  可以子类化QCustomEvent,加上别的成员,但是需要在customEvent()中转换QCustomEvent到特有的类型

事件的处理与过滤

  Qt的事件可以在五个不同的层次上被处理

  1.重新实现一个特定的事件handler

    QObject与QWidget提供了许多特定的事件handlers,分别对应于不同的事件类型。(如paintEvent()对应paint()事件)

  2.重新实现QObject::event()

    event()函数是所有对象事件的入口,QObject和QWidget中缺省的实现是简单地把事件推入特定的事件handlers。

   3.在QObject上安装事件过滤器

     事件过滤器是一个对象,它在事件到达指定目标之前接收这些事件。

   4.在aApp上安装一个事件过滤器

     它会监视程序中发送到所有对象的所有事件

   5.重新实现QApplication::notify()

     Qt的事件循环与sendEvent()调用这个函数来分发事件,

特定对象的事件处理

  一些事件类型可以被传递。这意味着加入目标对象不处理一个事件,Qt会试着寻找另外的事件接收者。用新的目标来调用QApplication::notify()。举例来讲,key事件是传递的,假如拥有焦点的Widget不处理特定键,Qt会分发相同的事件给父widget,然后是父亲的父亲,直到最顶层widget。

什么时候该接收事件,什么时候该忽略

  通过accept()函数和ignore()函数。可被传递的事件有一个accept()函数和一个ignore()函数,可以用他们来告诉Qt,你"接收"或是"忽略"这个事件。假如事件handler调用accept(),这个事件将不会再被传递。假如事件handler调用ignore(),Qt会试着查找另外的事件接收者。

来源:http://www.cnblogs.com/li-hao/archive/2011/11/13/2247662.html

Qt的事件的更多相关文章

  1. Qt的事件模型(5种使用办法,通常重新实现event handler即可。只有定义控件才需要管理信号的发射)

    Qt的事件模型 1.事件的概念 应用程序对象将系统消息接收为 Qt 事件.应用程序可以按照不同的粒度对事件加以监控.过滤并做出响应. 在 Qt 中,事件是指从 QEvent继承 的对象.Qt将事件发送 ...

  2. 剖析Qt的事件机制原理

    版权声明 请尊重原创作品.转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正. QT源码解析(一) QT创建窗口程序.消息循环和WinMai ...

  3. Qt 自定义事件详细实例(继承QEvent,然后QCoreApplication::postEvent()、sendEvent())

    创建用户事件 创建一个自定义类型的事件,首先需要有一个事件号,其值通常大于QEvent::User.为了传递事件信息,因此必须编写自定义的事件类,该事件类从QEvent继承. 编写用户事件:编写用户事 ...

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

    Qt中事件分发源代码剖析 Qt中事件传递顺序: 在一个应该程序中,会进入一个事件循环,接受系统产生的事件,并且进行分发,这些都是在exec中进行的.下面举例说明: 1)首先看看下面一段示例代码: in ...

  5. Qt中事件分发源代码剖析

    Qt中事件分发源代码剖析 Qt中事件传递顺序: 在一个应该程序中,会进入一个事件循环,接受系统产生的事件,并且进行分发,这些都是在exec中进行的. 下面举例说明: 1)首先看看下面一段示例代码: i ...

  6. 界面编程之QT的事件20180727

    /*******************************************************************************************/ 一.事件 1 ...

  7. QT paintevent 事件, update()槽函数

    一界面重载函数 使用方法: 1在头文件里定义函数 protected: void paintEvent(QPaintEvent *event); 2 在CPP内直接重载 void ---------- ...

  8. Qt中事件分发源码剖析

    Qt中事件分发源码剖析 Qt中事件传递顺序: 在一个应该程序中,会进入一个事件循环,接受系统产生的事件,而且进行分发,这些都是在exec中进行的. 以下举例说明: 1)首先看看以下一段演示样例代码: ...

  9. Qt 自定义事件(三种方法:继承QEvent,然后Send Post就都可以了,也可以覆盖customEvent函数,也可覆盖event()函数)

    Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展.在 Qt 中,你需要继承的类是 QEvent. 继承QEvent类,你需要提供一个QEvent::Type类型的参数,作为自定 ...

随机推荐

  1. 深入理解redis数据类型

    转载请注明出处:https://www.cnblogs.com/wenjunwei/p/9720033.html redis的存储模型 redis不是普通的键值对存储,它实际上是一个数据结构存储服务器 ...

  2. Django 系列博客(一)

    Django 系列博客(一) 前言 学习了 python 这么久,终于到了Django 框架.这可以说是 python 名气最大的web 框架了,那么从今天开始会开始从 Django框架的安装到使用一 ...

  3. 使用Task异步执行方法_多线程_应用程序池

    偶然遇到在执行登录的方法需要发送消息队列导致登录时间过长的问题,从网上查了一些方法,先将一个简单的异步处理程序的小例子展示出来,供大家参考: 备注:该方法是从应用程序程序所在的线程池中获取线程,第一次 ...

  4. WPF,强制捕获鼠标事件,鼠标移出控件外依然可以执行强制捕获的鼠标事件

    在WPF中,只有鼠标位置在某个控件上的时候才会触发该控件的鼠标事件.例如,有两个控件都注册了MouseDown和MouseUp事件,在控件1上按下鼠标,不要放开,移动到控件2上再放开.在这个过程中,控 ...

  5. 同一个dll 不同路径下注册 一个失败 一个成功

    一个路径下用regsvr32注册成功,一个注册失败,提示平台不兼容. 最后用depends查看依赖的dll,发现依赖的dll有问题,从注册成功的路径下复制一个过来,重新注册就成功了

  6. 【Java每日一题】20170117

    20170116问题解析请点击今日问题下方的“[Java每日一题]20170117”查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; import jav ...

  7. 《Redis开发与运维》读书笔记

    一.初始Redis 1.Redis特性与优点 速度快.redis所有数据都存放于内存:是用C语言实现,更加贴近硬件:使用了单线程架构,避免了多线程竞争问题 基于键值对的数据结构,支持的数据结构丰富.它 ...

  8. 使用eclipse初步学习vue.js的基本操作 ①

    一.vue.js的初步认识 <a href="https://unpkg.com/vue ">vue.js下载</a> 1.抛开手动操作DOM的思维,Vue ...

  9. blfs(systemd版本)学习笔记-构建google-chrome浏览器

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 一.google-chrome浏览器官网下载地址 我只找到了deb包和rpm包的下载地址 1.https://dl.google ...

  10. js 冒泡排序、快速排序、去重、查找字符串最多值(面试常有)

    冒泡排序 var bubbleSort = function(arr) { for (var i = 0; i < arr.length-1; i++) { for (var j = i+1; ...