在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. mysql的binlog太多太大占用了空间的解决办法

    现象:网站访问越来越慢,最后无法访问了,经过检查发现磁盘满了 分析过程及解决方案:通常出现这种问题都应该登录服务器检查磁盘.内存和进程使用的情况,通过top.df –h和free –m来检查,发现磁盘 ...

  2. org.eclipse.core.resources.bak文件导致MyEclipse每次关闭时无法保存文件

    MyEclipse关闭时提示如下信息 Problems occurred while trying to save the state of the workbench. Internal Error ...

  3. SQLite connection strings

    Basic Data Source=c:\mydb.db;Version=3; Version 2 is not supported by this class library. SQLite In- ...

  4. 一致性问题和Raft一致性算法——一致性问题是无法彻底解决的,可以说一个分布式系统可靠性达到99.99…%,但不能说它达到了100%

    一致性问题 一致性算法是用来解决一致性问题的,那么什么是一致性问题呢? 在分布式系统中,一致性问题(consensus problem)是指对于一组服务器,给定一组操作,我们需要一个协议使得最后它们的 ...

  5. window操作常识

  6. hibernate 框架搭建

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自 ...

  7. http接口测试框架-遇到的问题

    遇到过很多问题 如图,结果做作对比的时候,发现返回的结果有一个error_code: 0,中间有一个空格,导致对比失败 解决方法:打印出结果,再对比,case里的预期结果是否一致,有时候是填写的错误 ...

  8. 关于CString与VARIANT(CComVariant)之间的转化

    一.VARIANT.CComVariant类与CString是什么: CString是MFC定义的字符串类,VARIANT是COM标准为了使COM组件能够被各种语言使用(vc++.vb.java.py ...

  9. codeforces 707D D. Persistent Bookcase(dfs)

    题目链接: D. Persistent Bookcase time limit per test 2 seconds memory limit per test 512 megabytes input ...

  10. 【leetcode刷题笔记】Sum Root to Leaf Numbers

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...