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. [PHP] php + phpstudy + phpstrom + xdebug + postman开启调试

    主体 php + phpstudy + phpstrom + xdebug + postman + vue + chrome 使用的是前后端分离的开发方式,vue 在 webpack 通过代理进行请求 ...

  2. mysql中的prepare介绍和应用

    简单的用set或者declare语句定义变量,然后直接作为sql的表名是不行的,mysql会把变量名当作表名.在其他的sql数据库中也是如此,mssql的解决方法是将整条sql语句作为变量,其中穿插变 ...

  3. [android] 采用layoutInflater打气筒创建一个view对象

    上一节知道了ListView的工作原理,数据也展示出来了,但是TextView显示的非常难看,如果想美化一下,就先创建好一个布局出来,这个布局采用了两层LinearLayout嵌套,外层的水平方向,内 ...

  4. [PDOException] PDO::__construct(): php_network_getaddresses: getaddrinfo failed:

    执行数据迁移 php artisan migrate 报错: 网上很多资料说开启allow_open_url等其实没卵用...貌似问题出在dns上....原来数据库的配置是这样的 DB_CONNECT ...

  5. 8. 同步锁Lock

    package com.gf.demo07; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Ree ...

  6. 【Java每日一题】20170314

    20170313问题解析请点击今日问题下方的“[Java每日一题]20170314”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...

  7. Golang 正则表达式Regex相关资料整理

    Golang 支持的正在表达式是 https://github.com/google/re2/wiki/Syntax 注意这里提示 NOT SUPPORTED的。 工具 一些测试正则表达式的工具 推荐 ...

  8. 老王带你走过 Kafka 入门教程

    Apache Kafka是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统. 它最初由LinkedIn公司开发. Linkedin于2010年贡献 ...

  9. linux mail操作

    本操作系统邮件由来,crontab定时任务执行推送产生. 1.查看有多少封邮件 & file 2.我们直接键入23935来访问这封mail,看看是否是我们所需要的最新邮件. 3. 退出邮件查看 ...

  10. es6 语法 (map、set和array 的对比)

    //数据结构对比 增查改删 { //map和array对比 let map = new Map(); let array = []; //增 map.set('t',1); array.push({t ...