在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. 关于C++类的成员函数是否要加关键字“const”

    原则:类的成员函数在小括号后大括号前加上 const ,代表不准备改变对象的数据.不加的话代表有可能会改变对象的数据. 1.当常量对象,就是加上const修饰的类的成员去调用常量成员函数时,这表示:对 ...

  2. 翻译Lanlet2

    Here is more information on the basic primitives that make up a Lanelet2 map. Read here for a primer ...

  3. CSS3 3D立体柜子实现

    1. [图片] 20140811233657.jpg 2. [图片] 120140811233846.jpg ​3. [代码][CSS]代码 body {      background-color: ...

  4. spring学习(5)

    bean配置 启用注解 <context:annotation-config/> 使用spring的特殊bean 对bean BeanPostProcessor spring本身提供的特殊 ...

  5. 英语发音规则---(e)s和-(e)d的读音规则

    英语发音规则---(e)s和-(e)d的读音规则 一.总结 一句话总结: 1.大部分可数名词的复数及动词第三人称单数的一般现在式,是以-(e)s结尾的? moths,glasses:digs,teac ...

  6. HTML5学习笔记——1

    1.视频 <vedio src  controls  height width autoplay loop preload > </vedio> <source src ...

  7. 深度学习—BN的理解(二)

    神经网络各个操作层的顺序: 1.sigmoid,tanh函数:conv -> bn -> sigmoid -> pooling 2.RELU激活函数:conv -> bn -& ...

  8. linux命令学习笔记(37):date命令

    在linux环境中,不管是编程还是其他维护,时间是必不可少的,也经常会用到时间的运算,熟练运用date命令 来表示自己想要表示的时间,肯定可以给自己的工作带来诸多方便. .命令格式: date [参数 ...

  9. stl_list.h

    stl_list.h // Filename: stl_list.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: http://b ...

  10. Java中日期和时间的相关问题

    1.java.lang.System类 System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位 ...