The Event System

在Qt中,事件是继承了虚拟类QEvent的对象,它代表了程序所发生的事情或者程序需要知道的一个外部活动的结果。事件可以被任意 QObject子类的实例接收和处理,是与widgets密切相关。本文描述了在一个典型的程序中事件是如何被传送和处理的。

How Events are Delivered

当发生一个事件,Qt通过构造一个适当的 QEvent子类的实例来创建事件对象来代表它,并通过调用vevent()函数把它传送到特定的 QObject 实例。

该函数本身不处理事件:根据传送的事件类型,它为特定的时间类型调用一个事件处理程序,并根据事件是被接受或忽略发送一个响应。

一些事件,如QMouseEvent 和 QKeyEvent来自windows系统。如QTimerEvent, 来自其他来源,一些来自程序本身。

Event Types

大多数的事件类型有特别的类,尤其是 QResizeEvent, QPaintEvent, QMouseEvent, QKeyEvent,andQCloseEvent. ,它们都继承了QEvent 和添加了特殊的函数。如 QResizeEvent 添加了 size()和 oldSize()函数使得widgets 可以获得其改变的规模。

一些类支持多于一种实际的事件类型。 QMouseEvent 支持鼠标按下,双击,移动和其他相关操作。

每个事件都有一个定义在QEvent::Type的相关的类型,它可以用作运行时的类型信息以快速确定事件对象是构造自哪个子类。

由于程序需要多种复杂的方式的响应,Qt的事件传送机制也是灵活的。QCoreApplication::notify()文档对称进行了确切的描述。

Event Handlers

通常事件被传送的方法是调用一个虚函数。例如, QPaintEvent 通过调用 QWidget::paintEvent().而被传送。该虚函数复杂作出适当的响应,通常是重绘widget。如果在你实现的虚函数里不能完成所需要的功能,可以调用基类的实现。

例如,下面的代码处理了自定义的checkbox 鼠标左键按下事件,把其他按键按下的事件传送给基类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拦截事件来移动键盘焦点,但是有的widget需要自己处理Tab 按下事件。

这些对象可以重新实现 QObject::event(),,一般的事件处理程序,可以在通常的事件处理之前或之后对它们的事件进行处理,或者完全取代整个函数的。一个既拦截Tab 也有自定义事件的widget 可能包含以下的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
        returntrue;
    }
    } elseif (event->type() == MyCustomEventType) {
    MyCustomEvent *myEvent =static_cast<MyCustomEvent *>(event);
    // custom event handling here
    returntrue;
    }
 
    returnQWidget::event(event);
}

我们注意到对于没有处理的所有情况都调用了QWidget::event() ,而且返回值表明了事件是否被处理。返回值true阻止了事件被传递给其他对象。

Event Filters

有时一个对象需要检查并可能拦截被传送给其他对象的事件。例如,对话框一般需要为一下widget过滤键盘按键事件。例如,修改返回键处理。

QObject::installEventFilter()设置了eventfilter,,在目标对象的QObject::eventFilter() 函数里接收事件。事件过滤器在目标对象之前处理事件,根据需要允许对事件进行检查和丢弃。可以用 QObject::removeEventFilter()函数移除一个已经存在的事件过滤器。

当一个过滤器对象的eventFilter() 实现被调用,它可以接受或不接受事件,允许或拒绝更进一步的处理事件。如果所有的事件过滤器允许更进一步的处理事件,事件将被发送给目标对象本身。如果其中某个事件停止处理,目标对象和后面一些事件过滤器都接收不到该事件。

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
            returntrue;
        } else
            returnfalse;
    }
    returnfalse;
}

以上代码演示了另一种拦截Tab按键事件并发送到特定目标widget的方法。在这种情况下,事件过滤器处理了相关的事件并返回true阻止事件被进一步处理。其他的事件则被忽略,事件过滤器返回false以允许它们被发送到目标widget,通过任何已经安装的事件过滤器。

为整个程序过滤所有的事件也是可能的,通过为 QApplication 或QCoreApplication 安装事件过滤器。这样的全局事件过滤器将会在特定对象的过滤器之前被调用。这很强大,但是也会使得整个程序的事件发送变慢。

Sending Events

很多程序想创建和发送自己的事件。你可以用像Qt的事件循环一样的方法发送事件,通过构造合适的事件对象并用QCoreApplication::sendEvent()和QCoreApplication::postEvent().发送事件。

sendEvent()立即处理事件。当它返回,事件过滤器和对象本身已经处理了事件。对于很多事件类型,有一个isAccepted()函数用来获取最近的处理过程事件是被接受还是不被接受。

postEvent()把事件传递到队列等待分发。下一次主事件循环运行,它进行一些优化将分发所有的队列中的事件。例如,有一些resize 事件,将被压缩成一个事件。同样的应用与paint事件:QWidget::update()调用 postEvent(),它消除闪烁和增加速度以避免多次重绘。

postEvent()在对象初始化过程中也被用到,因为发出的事件将在对象的初始化完成之后立即分发。当实现一个widget,意识到事件可能在其生命期的早期被分发这很重要,在其构造函数中,确保在早期初始化成员变量,在其有机会接收到事件之前。

要创建自定义的事件类型,需要定义一个事件号,必须大于 QEvent::User.

The Event System相关推荐

  1. 3dsmax Node Event System

    Node Event System 3dsmax 节点事件系统 https://help.autodesk.com/view/MAXDEV/2022/ENU/?guid=GUID-7C91D285-5 ...

  2. A Type-Safe Event System for Unity3D

    转载自:http://www.willrmiller.com/?p=87 The Event Listener pattern is an extremely common design patter ...

  3. Qt事件体系概述(The Event System)

    本文译自https://doc.qt.io/qt-5/eventsandfilters.html,是意译. 目录 事件的发送(How Events are delivered) 事件类型(Event ...

  4. UICamera(NGUI Event system)原理

    看了UICamera的源码就显而易见了: UICamera « on: November 21, 2013, 12:21:48 AM » Overview UICamera is a somewhat ...

  5. 利用System.EventHandler来实现两个窗体间的事件调用

    在.NET中,窗体也被定义为一个类,所以要想调用窗体中的某个方法,除了要将要调用的方法设为public外,还得创建一个窗体类的实例.然而,在下面这种情况下,就是当我们打开了窗体1(有了此窗体的一个实例 ...

  6. 你知道event库吗?教你如何写一个自己的event库

    在使用BmobSDK开发App的时候,会有很多异步回调,类似如登录成功,插入数据成功的事件,虽然V3.5.0开始内部用rxjava去重构,也提供了rx风格的api,不过写事件回调的方法还是比较烦,这时 ...

  7. login控件authenticate_Login.Authenticate 事件 (System.Web.UI.WebControls) | Microsoft Docs

    验证用户的身份后出现.Occurs when a user is authenticated. public: event System::Web::UI::WebControls::Authenti ...

  8. EventBus VS Spring Event

    EventBus VS Spring Event 本地异步处理,采用事件机制 可以使 代码解耦,更易读.事件机制实现模式是 观察者模式(或发布订阅模式),主要分为三部分:发布者.监听者.事件. Gua ...

  9. Android system server之WindowManagerService按键消息传播流程

    主要涉及的文件有: WindowManagerService.java   frameworks\base\services\java\com\android\server\ PhoneWindow. ...

最新文章

  1. 聚集索引和非聚集索引- -
  2. rgb红色范围_UI设计教程分享之RGB与CMYK色彩模式对比
  3. alright alright alright
  4. ASP.NET 2.0 - 选用DataSet或DataReader
  5. 【开源框架】:解决方案级别的代码生成器 WebFirst
  6. Oracle连接字符串记录
  7. STM32----摸石头过河系列(一)
  8. IDEA中Git的更新、提交、还原方法
  9. springmvc重定向到另一个项目_SpringMVC结合Ajax、请求转发重定向、视图解析器
  10. reviewboard mysql_【ReviewBoard】安装与配置
  11. GPU卡的主流调度平台
  12. ios中获得UUID的方法,ios怎么获得uuid
  13. 2012网站服务器目录磁盘满了,服务器磁盘异常爆满的原因及解决方法
  14. 重装Win10系统之U盘启动盘的制作(详细教程)
  15. python小技巧:一步步教你用Python实现
  16. 一篇文章带你认识 Java 异常以及如何处理异常
  17. 2021-09-30-THZ-前置
  18. matlab A律PCM编码原理框图,求大神,讲解A律PCM编码吖
  19. 调用阿里云身份证识别OCR
  20. 2022半导体芯片人才市场趋势报告

热门文章

  1. 用Python连接MySQL并进行CRUD
  2. 使用软链接的方式迁移Docker
  3. 算法入门篇 一 时间复杂度
  4. 京东商城上市带来的利与益
  5. windows平台下vlc编译
  6. 面试风云录(01) - 怎样回答这两个问题?
  7. 解决:There was an unexpected error (type=Internal Server Error,..). No instances available for XXX
  8. MongoDB监控及报警
  9. PyTorch Softmax
  10. 利用redis实现分布式锁:加锁与解锁