【Qt】Qt事件系统

00. 目录

在这里插入图片描述

01. Qt事件系统概述

Qt 5.12

​ Qt Core

​ The Event System

在Qt中,事件是对象,派生自抽象 QEvent 类,表示应用程序内部发生的情况或应用程序需要了解的外部活动的结果。事件可以由任何 QObject 子类接收和处理,但它们与widgets控件特别相关。本文档介绍事件如何在典型应用程序中传递和处理。

02. 事件如何传递

当事件发生时,Qt创建一个事件对象来表示它,方法是构造一个适当的实例 QEvent 子类,并将其传递给 QObject (或其子类之一)通

过调用其 event() 函数。

此函数本身不处理事件;根据传递的事件的类型,它调用该特定类型事件的事件处理程序,并根据事件是被接受还是被忽略来发送响应。

一些事件,例如 QMouseEventQKeyEvent,来自窗口系统;有些,如 QTimerEvent,来自其他来源;有些来自应用程序本身。

03. 事件类型

大多数事件类型都有特殊类,特别是 QResizeEventQPaintEventQMouseEventQKeyEventQCloseEvent.每个 QEvent 子类并

添加特定事件的函数。例如 QResizeEvent 增加 size()oldSize() 以使widgets控件能够发现其尺寸是如何更改的。

某些类支持多个实际事件类型。 QMouseEvent 支持鼠标按钮按下、双击、移动和其它相关操作。

每个事件都有一个关联的类型,定义于 QEvent::Type,这可以用作运行时类型信息的便捷来源,以快速确定给定事件对象的构造自哪个

子类。

由于程序需要以各种复杂的方式做出反应,Qt的事件传递机制非常灵活。 QCoreApplication::notify()相关文档简明扼要地讲述整个过

程; Qt季刊 文章 Another Look at Events 简洁地重述它。在这里,我们将为95%的应用程序进行足够的解释。

04. 事件处理

传递事件的正常方法是调用虚函数。例如 QPaintEvent 被传递传递通过调用 QWidget::paintEvent()方法。这个虚函数负责做出适当的

反应,通常是通过重新绘制widget控件。如果在虚拟函数的实现中没有执行所有必要的工作,则可能需要调用基类的实现。

例如,以下代码处理在自定义复选框小部件上单击鼠标左键事件,同时将所有按钮其它单击事件传递到基 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 截获这些以移动键盘

焦点,但有一些控件需要 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值防止将事件发送给其他对象。

05. 事件过滤器

有时,对象需要查看(可能还需要拦截)传递给另一个对象的事件。例如,对话框通常需要过滤某些Widget控件的按键; 例如,修改返回键

事件处理。

QObject::installEventFilter()函数通过设置一个事件过滤器来实现这一点,使指定的过滤器对象在其QObject::eventFilter()函数中接收目

标对象的事件。事件过滤器在目标对象处理事件之前处理事件,允许它根据需要检查和丢弃事件。现有的事件过滤器可以使用

QObject::removeEventFilter()函数删除。

当过滤器对象的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;
 }

上面的代码显示了拦截发送到特定目标widget控件的Tab键按下事件的另一种方法。在这种情况下,过滤器处理相关事件并返回true以阻

止它们被进一步处理。所有其他事件都被忽略,过滤器返回false以允许它们通过安装在目标控件上的任何其他事件过滤器发送到目标控

件。

通过在QApplication或QCoreApplication对象上安装事件过滤器,也可以过滤整个应用程序的所有事件。在特定于对象的过滤器之前调用此类全局事件过滤器。这是非常强大的,但它也减慢了整个应用程序中每个事件的事件传递;通常应该讨论使用其他技术。

06. 事件发送

许多应用程序都希望创建和发送它们自己的事件。通过构造合适的事件对象并使用QCoreApplication::sendEvent()和

QCoreApplication::postEvent()发送事件,您可以以与Qt自己的事件循环完全相同的方式发送事件。

sendEvent()立即处理事件。当它返回时,事件过滤器和/或对象本身已经处理了事件。对于许多事件类,都有一个名为isAccepted()的函

数,它告诉您事件是被最后调用的处理程序接受还是拒绝。

postEvent()将事件发送到队列中以供以后调度。下次Qt的主事件循环运行时,它会调度所有发布的事件,并进行一些优化。例如,如果

有多个调整大小事件,它们将被压缩为一个事件。这同样适用于绘制事件:QWidget::update()调用postEvent(),这消除了闪烁并通过避免

多次重绘提高了速度。

postEvent()也在对象初始化期间使用,因为提交的事件通常会在对象初始化完成后很快被分派。在实现widget控件时,重要的是要认识到,事件可以在其生命周期的早期传递,因此,在其构造函数中,一定要在早期初始化成员变量,以免它有可能接收到事件。

要创建自定义类型的事件,您需要定义一个事件号,该事件号必须大于QEvent::User,并且您可能需要创建QEvent的子类,以便传递关

于自定义事件的特定信息。有关详细信息,请参阅QEvent文档。

附录

关键词: The Event System

参考:The Event System

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/132447669