写在前面

在 Qt 中,事件分发器(Event Dispatcher)是一个核心概念,用于处理 GUI 应用程序中的事件。事件分发器负责将事件从一个对象传递到另一个对象,直到事件被处理或被取消。

每个继承自QObject或QObject的类都可以在本类中重写bool event(QEvent *e),来实现相关事件的捕获和拦截。

事件分发器的工作原理

event函数

每个继承自QObject或QObject的类都可以在本类中重写bool event(QEvent *e),来实现相关事件的捕获和拦截,原型如下:

bool event(QEvent *e);

e: 存储事件相关信息
返回值:返回true表示拦截处理,不再向下分发

这里使用一个简单的示例图帮助理解:

我们知道,没有application应用程序运行后,都有一个事件循环,即exec()。

每个事件都会有一个“四元组”标识事件来自哪个对象,哪个事件触发(信号),要发往哪个对象,使用哪个函数(槽)处理。

而事件分发器则工作在信号发往目的对象的这一阶段,即某一控件对象收到来自事件循环的某一需要该对象处理的事件(信号)时,就会进入到事件分发器,在事件分发器中,可以会有一些事件类型的判断,根据类型进行相应的处理(分发)。

例,在事件分发器中判断,若是鼠标按下事件,则使用mouPressEvent进行专门处理,若是鼠标移动事件,则使用mouseMoveEvent进行相应处理。

可以这样理解:

bool QLabel::event(QEvent* e){if (是鼠标按下事件){//调用mousePressEvent处理,mousePressEvent是虚函数,会动态调用对应版本mousePressEvent();return true;//返回true表示成功拦截处理}else if (鼠标移动事件){//同理,调用mouseMoveEvent虚函数进行相应处理mouseMoveEvent();return true;}//也可以继续分发给父类处理return QFrame::event(e);}

示例

这里在一个自定义的Label控件中拦截鼠标按下事件:

#ifndef MYLABEL_H#define MYLABEL_H#include >class MyLabel : public QLabel{Q_OBJECTpublic:explicit MyLabel(QWidget *parent = nullptr);//重写鼠标相关事件void enterEvent(QEnterEvent *event);void leaveEvent(QEvent *event);void mousePressEvent(QMouseEvent *ev);void mouseReleaseEvent(QMouseEvent *ev);void mouseMoveEvent(QMouseEvent *ev);//事件分发器bool event(QEvent *e);signals:};#endif // MYLABEL_H
#include "mylabel.h"#include #include #include MyLabel::MyLabel(QWidget *parent): QLabel{parent}{//设置鼠标追踪setMouseTracking(true);}//重写鼠标相关事件void MyLabel::enterEvent(QEnterEvent *event){qDebug() << "鼠标进入";}void MyLabel::leaveEvent(QEvent *event){qDebug() <button() == Qt::LeftButton){QString qs = QString("鼠标按下, x = %1, y = %2").arg(ev->x()).arg(ev->y());qDebug() << qs;}}void MyLabel::mouseReleaseEvent(QMouseEvent *ev){qDebug() <buttons() & Qt::LeftButton){QString qs = QString("鼠标移动了, x = %1, y = %2").arg(ev->x()).arg(ev->y());qDebug() <type() == QEvent::MouseButtonPress){qDebug() << "event 拦截鼠标按下事件";return true;}return QLabel::event(e);}

运行可以看到成功在event中拦截到鼠标按下事件,而不再继续分发调用mousePressEvent: