在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. hadoop集群增加新节点

    上次hadoop集群一块数据盘报警, 提交工单后维修人员更换硬盘 服务器是dell r720的, 8盘位, 蛋疼的是这些硬盘都是做的单盘raid1,维修人员说必须关机导入硬盘才能正常使用 (服务器就这 ...

  2. bzoj 1008: [HNOI2008]越狱 数学

    1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Description 监狱有连 ...

  3. mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高

    mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ... ...

  4. Django 模版当中使用中文 UnicodeDecodeError at / 问题

    Django 再次是当中字符编码问题 今天使用了bootstrap 当中的一些CSS 对自己的博客项目当中的一些东西进行美化 但是很奇怪的是 当 诸如按钮类的加入 中文字符后 就会提示 Unicode ...

  5. Netty组件理解(转载)

    转载的文章,写的非常好.   一.先纵览一下Netty,看看Netty都有哪些组件?        为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架 ...

  6. Oracle忘记用户名密码

    一.oracle 11g登录服务开启 成功安装Oracle 11g后,共有7个服务,这七个服务的含义分别为:1. Oracle ORCL VSS Writer Service:Oracle卷映射拷贝写 ...

  7. bzoj 3545: [ONTAK2010]Peaks Kruskal重构树

    题目: 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经 ...

  8. 【LeetCode】001. Two Sum

    题目: Given an array of integers, return indices of the two numbers such that they add up to a specifi ...

  9. 分立元件封装尺寸及PCB板材工艺与设计实例

    分立元件封装尺寸 inch mm (L)mm (w)mm (t)mm (a)mm (b)mm 0201 0603 0.6±0.05 0.30±0.05 0.23±0.05 0.10±0.05 0.60 ...

  10. shader学习推荐

    <DirectX 9.0 3D游戏开发编程基础> 当您理解了如何实现顶点着色器和像素着色器之后,接下来您可能想进一步了解使用这两种着色器能够实现哪些效果. 最好的方式就是研究一下现有的各种 ...