在Qt中,事件对象都继承于QEvent类,它表示应用程序内部或由于应用程序需要了解的外部活动而发生的事情。事件可以由QObject子类的任何实例接收和处理,尤其是widget。本文档描述如何在典型应用程序中交付和处理事件。

事件的传递

事件发生时,Qt创建事件对象(QEvent的适当的子类),调用要传递到的QObject的实例的event()方法,完成事件的传递。

event()方法本身不处理事件;它根据其传递的事件类型,调用对应的事件处理程序,并给句事件是否被接受或忽略来发出响应。

事件可以来自系统(QmouseEvent和QKeyEvent);可以是其他来源(QTimerEvent);可以来源于应用本身。

事件类型

大多数事件类型都有其特定的类,常见的如QResizeEvent、QPaintEvent、QMouseEvent、QKeyEvent和QCloseEvent。每个类都是QEvent的子类,并添加特定于事件的函数。例如,QResizeEvent添加了size()和oldSize(),使widgets能够发现它们的维度是如何更改的。

有些类支持多个实际事件类型。QMouseEvent支持按下鼠标按钮、双击、移动和其他相关操作。

每个事件都有一个关联的类型(在QEvent::type中定义),作为一个方便的运行时类型信息源,可以快速确定给定的事件对象是由哪个子类构造的。

由于程序需要以多种复杂的方式进行响应,Qt的事件交付机制是灵活的。QCoreApplication::notify()的文档简明地描述了整个过程;Qt季刊 Another Look at Events 不那么简洁地再次讨论了它。在这里,我们将为95%的应用程序提供足够的解释。

事件处理程序

传递事件后的通常方法是调用虚函数。例如,QPaintEvent是通过调用QWidget::paintEvent()来传递的。这个虚拟函数负责做出适当的反应,通常是通过重新绘制小部件。如果没有在虚函数的实现中执行所有必要的工作,则可能需要调用基类的实现。

例如,下面的代码处理自定义复选框小部件上的鼠标左键单击,同时将所有其他按钮单击传递给基本的QCheckBox类:

void MyCheckBox::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
// handle left mouse button here
} else {
// pass on other buttons to base class
QCheckBox::mousePressEvent(event);
}
}

如果要替换基类的函数,必须自己实现所有内容。但是,如果您只想扩展基类的功能,那么您可以实现您想要的,并调用基类来为您不想处理的任何情况获得默认行为。

有时候,没有一个特定于事件的函数,或者特定于事件的函数是不够的。最常见的例子是按Tab键。正常情况下,QWidget会截取这些内容来移动键盘焦点。但如果widgets本身需要Tab键,就需要下面的方法。

可以重新实这些对象的现通用事件处理程序QObject::event(),或者在常规处理之前或之后执行事件处理,或者完全替换函数。一个非常不寻常的小部件,既需要Tab,又有一个特定于应用程序的自定义事件,它可能包含以下event()函数:

bool MyWidget::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Tab) {
// special tab handling here
return true;
}
} else if (event->type() == MyCustomEventType) {
MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event);
// custom event handling here
return true;
} return QWidget::event(event);
}

注意,对于所有未处理的情况,QWidget::event()仍然被调用,返回值指示是否处理了事件;true值阻止事件被发送到其他对象。

事件过滤器

有时,一个对象需要查看并可能拦截传递给另一个对象的事件。例如,对话框通常希望过滤某些小部件的按键;例如,修改返回键处理。

QObject::installEventFilter()安装一个事件过滤器,这个过滤器在目标对象的QObject::eventFilter()中接收事件。事件过滤器在目标对象处理事件之前处理事件,允许它根据需要检查和丢弃事件。可以使用QObject::removeEventFilter()函数删除现有的事件过滤器。

当调用filter对象的eventFilter()实现时,它可以接受或拒绝事件,并允许或拒绝事件的进一步处理。如果所有事件过滤器都允许对事件进行进一步处理(返回false),则将事件发送到目标对象本身。如果其中一个停止处理(返回true),则目标和任何后续的事件过滤器都无法看到该事件。

bool FilterObject::eventFilter(QObject *object, QEvent *event)
{
if (object == target && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// Special tab handling
return true;
} else
return false;
}
return false;
}

上面的代码显示了拦截发送到特定目标小部件的Tab键按事件的另一种方法。在本例中,过滤器处理相关事件并返回true,以阻止它们进一步被处理。所有其他事件都被忽略,过滤器返回false,以便通过安装在其上的任何其他事件过滤器将它们发送到目标小部件。

通过在QApplication或QCoreApplication对象上安装事件过滤器,还可以过滤整个应用程序的所有事件。这样的全局事件过滤器的处理顺序优先于特定对象的事件过滤器。这是非常强大的,但它也降低了整个应用程序中每个事件的事件交付速度;通常应该使用讨论的其他技术。

发送事件

许多应用程序都希望创建和发送自己的事件。您可以通过构造合适的事件对象,并使用QCoreApplication::sendEvent()和QCoreApplication::postEvent()发送事件,从而以与Qt自己的事件循环完全相同的方式发送事件。

sendEvent()立即处理事件。当它返回时,事件过滤器和/或对象本身已经处理了事件。对于许多事件类,都有一个名为isAccepted()的函数,它告诉您上次调用的处理程序是否接受或拒绝了该事件。

postEvent()将事件发布到队列中,以便稍后进行分派。下一次Qt的主事件循环运行时,它会分派所有已发布的事件,并进行一些优化。例如,如果有多个调整大小事件,则将它们压缩为一个。同样的情况也适用于绘制事件:QWidget::update()调用postEvent(),它通过避免多次重绘来消除闪烁并提高速度。

要创建自定义类型的事件,您需要定义一个事件编号,该编号必须大于QEvent::User,并且您需要继承QEvent的子类,以便传递关于自定义事件的特定信息。有关详细信息,请参阅QEvent文档。

【Qt文档阅读】事件系统的更多相关文章

  1. Qt文档阅读笔记-QGraphicsItem::paint中QStyleOptionGraphicsItem *option的进一步认识

    官方解析 painter : 此参数用于绘图;option : 提供了item的风格,比如item的状态,曝光度以及详细的信息:widget : 想画到哪个widget上,如果要画在缓存区上,这个参数 ...

  2. 【Qt文档阅读】Window and Dialog Widgets

    Window and Dialog Widgets 没有嵌入到父控件中的控件(widget)称之为窗口(window).通常窗口带有边框和标题栏. Windows通常集成到桌面环境中,并且在某种程度上 ...

  3. 生成 Qt 文档

    个人总结    从命令行进入Qt安装目录     设置环境变量     set path=D:/mingw32/bin;D:/Qt/5.0.0/qtbase/bin;D:/icu/bin;D:/icu ...

  4. Node.js的下载、安装、配置、Hello World、文档阅读

    Node.js的下载.安装.配置.Hello World.文档阅读

  5. 我的Cocos Creator成长之路1环境搭建以及基本的文档阅读

    本人原来一直是做cocos-js和cocos-lua的,应公司发展需要,现转型为creator.会在自己的博客上记录自己的成长之路. 1.文档阅读:(cocos的官方文档) http://docs.c ...

  6. 转:苹果Xcode帮助文档阅读指南

    一直想写这么一个东西,长期以来我发现很多初学者的问题在于不掌握学习的方法,所以,Xcode那么好的SDK文档摆在那里,对他们也起不到什么太大的作用.从论坛.微博等等地方看到的初学者提出的问题,也暴露出 ...

  7. Keras 文档阅读笔记(不定期更新)

    目录 Keras 文档阅读笔记(不定期更新) 模型 Sequential 模型方法 Model 类(函数式 API) 方法 层 关于 Keras 网络层 核心层 卷积层 池化层 循环层 融合层 高级激 ...

  8. Django文档阅读-Day1

    Django文档阅读-Day1 Django at a glance Design your model from djano.db import models #数据库操作API位置 class R ...

  9. Django文档阅读-Day2

    Django文档阅读 - Day2 Writing your first Django app, part 1 You can tell Django is installed and which v ...

随机推荐

  1. tkinter窗口系列之一——列表框

    以下内容来自https://tkdocs.com/tutorial/morewidgets.html 一个列表框显示由单行文本所组成的一栏条目,通常它很冗长,它允许使用者通过列表浏览其中的内容,选择一 ...

  2. java:解决eclipse配置Tomcat时找不到server选项

    http://blog.csdn.net/wugangsunny/article/details/25246565 集成Eclipse和Tomcat时找不到server选项: 按照网上的步骤如下: 在 ...

  3. 关于ios::sync_with_stdio(false);和 cin.tie(0)加速c++输入输出流

    原文地址:http://www.hankcs.com/program/cpp/cin-tie-with-sync_with_stdio-acceleration-input-and-output.ht ...

  4. Windows PCM音频捕获与播放实现

    在WINDOWS下,音频函数有多种类型,如MCI.多媒体OLE控制.高级音频等,使用方法都比较简单.但如果想编写一个功能较强大的音频处理程序,那就必须使用低级音频函数和多媒体文件I/O来控制音频设备的 ...

  5. 第K大子集-LH

    题解:搜索+二分 对于每个数有选与不选两种情况.然后我们先搜前一半的状态,每个数选还是不选. 有2^17种,然后我将每种状态拍一个序先存着.然后我再搜后一半的状态,2^18种. 假设后一半某一种情况的 ...

  6. 2006年清华:N的阶乘

    题目描述: 输入一个正整数N,输出N的阶乘. 输入: 正整数N(0<=N<=1000) 输出: 输入可能包括多组数据,对于每一组输入数据,输出N的阶乘 样例输入: 4 5 15 样例输出: ...

  7. Java类的生命周期(转)

    引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...

  8. java基础知识(11)---多线程

    多线程: 进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺 ...

  9. java基础知识(5)---继承

    继 承:(面向对象特征之一)好处:1:提高了代码的复用性.2:让类与类之间产生了关系,提供了另一个特征多态的前提. 父类的由来:其实是由多个类不断向上抽取共性内容而来的.java中对于继承,java只 ...

  10. 6.JasperReports学习笔记6-jasperreports和ssh工程整合

    转自:http://www.blogjava.net/vjame/archive/2013/10/12/404908.html 一.导入jasperreport相关jar包,这里采用当前比较稳定的5. ...