在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. 国内ADSL用户的带宽一般都是1M、2M、3M的,理论上的下载速度分别是128K/S、256K/S、384K/S。

    国内ADSL用户的带宽一般都是1M.2M.3M的,理论上的下载速度分别是128K/S.256K/S.384K/S. 1024/8===128      2048/8==256

  2. 【反思】一个价值两天的BUG,无论工作还是学习C语言的朋友都看看吧!

    博文原创,转载请联系博主! 使用C语言也有两个年头了,BUG写出来过不少,也改过不少BUG.但是偏偏就是有这么一个BUG让我手头的项目停工了两天,原因从百度找到谷歌,资料从MAN手册找到RFC也没有找 ...

  3. C、C++、Java、JavaScript、PHP、Python、Ruby 这些语言分别主要用来开发什么?

    C.C++.Java.JavaScript.PHP.Python.Ruby 这些语言分别主要用来开发什么? pansz,欢迎评论 此贴纯科普用,以下仅仅说主要用途,其他用途限于篇幅关系省略之,不要钻牛 ...

  4. matlab点云处理函数

    1. pcread: 输入文件名,返回pointCloud类(用于存储点云).eg: pcloud = pcread(“filename.ply”) 2. pcshow: 输入pointCloud类, ...

  5. HDU 2089 不要62:数位dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意: 问你在区间[n,m]中,有多少个数字不含"4"且不含"62 ...

  6. 未测试 Delphi读写UTF-8、Unicode格式文本文件

    // UTF-8文件写入函数 procedure SaveUTFFile(const FileName: string; S: string; WriteHeader: Boolean = True) ...

  7. (转)通过汇编语言实现C协程

    转自:http://www.cnblogs.com/sniperHW/archive/2012/06/19/2554574.html 协程的概念就不介绍了,不清楚的同学可以自己google,windo ...

  8. Havel-Hakimi定理(握手定理)

    Havel-Hakimi定理(握手定理) 由非负整数组成的非增序列s(度序列):d1,d2,…,dn(n>=2,d1>=1)是可图的,当且仅当序列: s1:d2 – 1,d3 – 1,…, ...

  9. [原]NYOJ-大数阶乘-28

    大学生程序代写 //http://acm.nyist.net/JudgeOnline/problem.php?pid=28 /*题目28题目信息运行结果本题排行讨论区大数阶乘 时间限制:3000 ms ...

  10. poj 1845 Sumdiv(约数和,乘法逆元)

    题目: 求AB的正约数之和. 输入: A,B(0<=A,B<=5*107) 输出: 一个整数,AB的正约数之和 mod 9901. 思路: 根据正整数唯一分解定理,若一个正整数表示为:A= ...