Qt事件处理流程

一.Qt事件处理

QT事件处理大概大概可以分为四个步骤:

QT事件机制
事件派发 ->事件过滤 ->事件分发 ->事件处理

  • 事件派发:事件派发 是由Qt框架(QApplication 对象)来完成的,它将当前应用程序产生的事件派发给对应的窗口

  • 事件过滤:事件在到达对应的窗口之前,可以被其他对象过滤、拦截、处理

  • 事件分发(一般事件处理):每个窗口都会有一个事件分发器,事件分发器会对事件进行分类,再将分好类的事件分发给对应的事件处理函数进行处理,每个事件处理函数的功能其实是非常单一的,只处理当前这一类事件

  • 事件处理(具体事件处理):窗口的事件处理函数,对当前事件进行处理

Qt中产生事件之后,整个的处理流程是这样:

1.当事件产生之后,Qt使用当前应用程序(QApplication)对象的notify函数将事件派发给对应的窗口

[override virtual] bool QApplication::notify(QObject* receiver,  QEvent* e); 
// receiver:接收事件的(窗口)对象
// e:事件

2.在事件到达对应的窗口之前,可以被其他的QObject对象截获和处理

[override virtual] bool QObject::eventFilter(QObject* target,  QEvent* e);
// target: 事件原本的接收(窗口)对象
// e:事件

在这里插入图片描述
3.当事件到达指定的窗口后, 窗口的事件分发器会对事件进行分类

[override virtual] bool QWidget::event(QEvent* event);

4:事件分配器对事件进行分类后,按事件的类型(鼠标事件, 键盘事件, resize事件 等等…),将事件分发给对应的具体的事件处理函数去处理,每个事件处理函数已经有默认实现, 我们也可以在子类中重写这些事件处理函数,列举几个事件处理函数:

[virtual] void paintEvent(QPaintEvent *event);
[virtual] void mousePressEvent(QMouseEvent* event);
[virtual] void enterEvent(QEvent *event);
[virtual] void leaveEvent(QEvent *event);

事件处理函数和事件过滤器

1.事件处理函数的作用是让某个具体的QObject对象处理其自己的事件,参考以上第4步;事件处理函数的返回值是void类型,参数为QxxEvent*;
对于某些类别的事件,如果在整个事件的派发和处理流程结束后还没有被处理,那么这个事件会向上转发给它的父Widget(QObject),直到事件到达顶层窗口,如果顶层窗口也不处理此事件,那么它将被视为未处理的事件,未处理的事件可能会有不同的处理方式,具体取决于事件类型和应用程序的设置。一般情况下,未处理的事件会被丢弃,不会对应用程序产生任何影响;
在有需要时,也可以通过重载顶层窗口的事件处理函数来处理未处理的事件。例如:

bool MainWindow::event(QEvent *event)
{
    if (event->type() == QEvent::UnhandledKeyRelease) {
        // 处理未处理的按键释放事件
        // ...
        return true; // 表示事件已经被处理
    }
    // 其他事件处理逻辑...

    return QMainWindow::event(event); // 调用父类的事件处理函数
}

QEvent是所有Qt事件类的基类,它提供了两个函数:ignore()和accept(),用于设置事件的处理状态
1.ignore()函数:

  • ignore()函数用于将事件标记为未被处理。调用ignore()函数后,表示事件不会被当前对象处理,并会继续向上级对象传递。
  • 如果一个对象在处理事件时调用了ignore()函数,那么该事件会被传递给父对象或者其他相关对象进行处理。
  • 通过调用ignore()函数,你可以让事件继续向上级对象传递,直到找到能够处理该事件的对象。

2.accept()函数:

  • accept()函数用于将事件标记为已被处理。调用accept()函数后,表示当前对象已经处理了该事件,其他对象将不会再接收到该事件。
  • 如果一个对象在处理事件时调用了accept()函数,那么该事件会被标记为已被处理,并且不会继续向上传递给其他对象。
  • 通过调用accept()函数,你可以告诉Qt框架该事件已经得到了处理,其他对象不需要再处理该事件。

这两个函数通常在具体的事件处理函数中调用,而且只有用在某些类别事件上是有意义的,这些事件就是上面提到的那些会被转发的事件,包括:鼠标、滚轮、按键等事件。

2.事件过滤器的作用是:在事件到达某个具体对象之前,将事件先处理一遍,参考以上第2步,事件过滤器函数的原型为:

bool QObject::eventFilter(QObject* target,  QEvent* e); 

bool 返回值表示此事件是否被处理,若返回true,表示该事件已经被处理,那么该事件将不会被传递到target对象;若返回false,则表示该事件还未被处理,此事件将继续传递给target对象去处理

二. QT事件机制

以上介绍了QT事件的处理流程,现在讲讲QT事件的产生。我们产生按照事件的来源,将事件分为两类:

  • 系统产生:由操作系统产生,比如鼠标消息,键盘消息,Qt将这些来自操作系统的消息,封装为对应的QEvent后进行事件处理
  • QT程序自己产生: 例如刷新QWidget,调用update()函数,就是QT系统自己 new 一个QEvent::UpdateRequest事件,然后调用 QApplication::postEvent();将事件放入消息队列,等待事件循环处理;若是立即绘制调用repaint()函数,也是new一个QEvent::UpdateRequest,调用QApplication::sendEvent(),不经过消息队列和事件循环,直接将事件派发并处理
void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime updateTime)
{
    if (!widget)
        return;
    switch (updateTime) {
    case UpdateLater:		//对应 update()函数
        QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
        break;
    case UpdateNow: {		//对应repaint()函数
        QEvent event(QEvent::UpdateRequest);
        QCoreApplication::sendEvent(widget, &event);
        break;
        }
    }
}
 [static] void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
// postEvent 是将事件投递到receiver所在线程的事件队列,等待事件循环来处理此事件
// 可以给别的线程发送事件。事件会在目的对象所属的线程中运行,异步接口
[static] bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
// sendEvent的事件会立即被处理,实际是调用QApplication::notify(),将事件派发并处理,跳过了事件队列和事件循环
//注意, sendEvent仅用于同一个线程之间发送事件。目的对象必须与当前线程一样

根据以上对QT事件处理的分析,我们可以得到5种级别的事件过滤办法,功能从弱到强:

  1. 重新实现部件的具体事件处理函数,如paintEvent()、mousePressvent()等。这也是最常用的方法
  2. 重新实现QObject的event()函数;(QObject: :event()函数可以在事件到达具体的事件处理函数之前获得该事件)
  3. 在对象上安装事件过滤器。(可以用于在一个界面类中同时处理不同子部件的不同事件,到达指定对象的所有事件,都会先经过这个事件过滤器)
  4. 给QApplication::instance()对象上安装事件过滤器,那么当前应用程序中所有的事件在发往任何其他的过滤器时,都要先经过当前这个事件过滤器
  5. 继承QApplication,重新实现notify()函数,可以在任何事件过滤器得到事件之前就获得他们
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值