QEvent类

QEvent 类是所有事件类的基类。事件对象包含事件参数。


Header:#include <QEvent>
CMake:find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake:QT += core
Inherited By:

QActionEvent

QChildEvent

QCloseEvent

QDragLeaveEvent

QDropEvent 

QDynamicPropertyChangeEvent

QExposeEvent

QFileOpenEvent

QFocusEvent

QGestureEvent

QGraphicsSceneEvent >

QHelpEvent

QHideEvent

QIconDragEvent 

QInputEvent

QInputMethodEvent

QInputMethodQueryEvent

QMoveEvent

QPaintEvent >

QPlatformSurfaceEvent

QResizeEvent

QScrollEvent

QScrollPrepareEvent

QShortcutEvent 

QShowEvent

QStateMachine::SignalEvent

QStateMachine::WrappedEvent

QStatusTipEvent

QTimerEvent

QWhatsThisClickedEvent

QWindowStateChangeEvent


【详细描述】

Qt主事件循环(QCoreApplication::exec()) 从事件队列中获取本地窗口系统事件,将它们转换为QEvent,并将转换后的事件发送到各 QObject

Qt中的事件会经过:派发 -> 过滤 -> 分发 -> 处理,4个阶段。

Qt对窗口中发生的事件有一系列的默认处理动作,用户可以在适当位置重写这些事件虚函数。

每个Qt应用程序都有一个唯一的QApplication应用程序对象,继承于QCoreApplication,调用它的exec()函数,便开启了Qt框架内部的事件循环机制。

int main(int argc,char* argv[])
{
    QApplication a(argc,argv);  //有且唯一的应用程序对象
    MainWindow* w = new MainWindow; 
    w.show();
    return a.exec();            //开启消息循环机制,进行事件的派发
}

Qt中产生事件后通过如下过程分发:

1.【派发】当事件产生后,通过QApplication应用程序对象调用重写的虚函数notify()将事件分发到指定的窗口:

//QObject *receiver 指向事件接收者,QEvent *e 指向产生的事件
[override virtual] bool QApplication::notify(QObject *receiver,QEvent *e)

2.【过滤】事件发送过程中,可以通过事件过滤器eventFilter()进行过滤,默认不过滤任何事件。

//QObject *watched指向要过滤事件的对象,QEvent *event指向要被过滤的事件
[virtual]bool QQbject::eventFilter(QObject *watched,QEvent *event)

3.【分发】未被过滤的事件会发送到指定的窗口,窗口的事件分发器event()会对收到的事件进行分类,并调用对应的事件处理器函数:

//QEvent *event指向应用程序派发且未被过滤的事件,分类后转给事件处理函数
[override virtual protected] bool QWidget::event(QEvent *event)

4.【处理】分类后的事件会交由对应的事件处理器函数,每个事件处理函数都有默认的处理动作,用户也可以重写这些事件处理函数,例如:

//鼠标按下
void QWidget::mousePressEvent(QMouseEvent *event)
//鼠标释放
void QWidget::mouseReleaseEvent(QMouseEvent *event)
//鼠标移动
void QWidget::mouseMoveEvent(QMouseEvent *event)
  • 上述事件处理函数都是“回调”函数,其调用过程由Qt框架完成,无需程序员干预。
  • 上述4个环节中事件处理器函数经常由程序员重写,以实现具体功能,它们主要分布在两个位置QObject类和QWidget类,前者只有一个timerEvent()定时器虚函数,后者有二十多个

通常,事件来自底层窗口系统 (系统事件,spontaneous() 返回真),但也可以使用 QCoreApplication::sendEvent()和QCoreApplication::postEvent() (应用程序内部事件,spontaneous() 返回假)。

QObjects 通过调用事件的 QObject::event() 函数来接收事件,该函数可以在子类中重新实现,以便自定义事件处理并添加其他事件类型。

★ QObjects 默认情况下,事件被调度给事件处理程序,如  QObject::timerEvent() 和 QWidget::mouseMoveEvent()。

QObject::installEventFilter() 允许一个对象截获发往另一个对象的事件。

QEvent 仅包含一个事件类型参数和一个“accept”标志,可以使用  accept() 设置或使用 ignore() 清除的 accept 标志。

accept 是默认设置的,但不要依赖它,因为子类可能会选择在其构造函数中清除它。

参阅 QObject::event(), QObject::installEventFilter(), QCoreApplication::sendEvent(), QCoreApplication::postEvent(), QCoreApplication::processEvents().


【公共类型】(枚举)

enumType { None, ActionAdded, ActionChanged, ActionRemoved, ActivationChange, …, MaxUser }该枚举类型定义了Qt中的有效事件,共140个左右。

【属性】

该属性保存事件对象的接受标志。


【公有函数】

QEvent(QEvent::Type type)构造type类型的事件对象。
virtual~QEvent()析构。如果是 posted,它将从要发布的事件列表中删除。
voidaccept()

事件对象的 accept 标志。

virtual QEvent *clone() const创建并返回此事件的相同副本。
voidignore()

清除事件对象的 accept 标志,等效于调用  setAccepted(false)。

清除 accept 参数表示事件接收器不需要该事件。不需要的事件可能会传递到父控件。

boolisAccepted() const访问函数,查看accept 。
boolisInputEvent() const如果事件对象是QInputEvent或者它的一个子类则返回true
boolisPointerEvent() const如果事件对象是QSinglePointEvent则返回true
boolisSinglePointEvent() const如果事件对象是QSinglePointEvent则返回true
virtual voidsetAccepted(bool accepted)

设置事件对象的 accept 标志,等效于调用 setAccepted(true)。

设置 accept 参数表示事件接收器需要该事件。不需要的事件可能会传递到父控件。

boolspontaneous() const如果事件源自应用程序外部(系统事件),则返回真,否则返回假。
QEvent::Typetype() const返回事件类型。

【静态公有成员】

intregisterEventType(int hint = -1)

注册并返回自定义事件类型。如果 hint 提供的值可用,则使用它,否则它将返回一个 QEvent::User 和 QEvent::MaxUser 之间(1000-65535)尚未注册的值。如果 hint 的值不在 QEvent::User 和 QEvent::MaxUser之间,则忽略 。

如果所有可用值都被占用或程序正在关闭,则返回 -1。


<<<返回根页面

<think>我们正在讨论Qt中的事件处理机制,特别是与输入事件(如键盘和鼠标事件)相关的部分。用户的问题集中在QEvent和QInputEvent上,希望了解Qt如何处理这些输入事件。 根据引用[1]和[2]的内容,我们知道: - Qt的事件机制借鉴了Windows的消息机制,但进行了跨平台的封装。 - 大多数事件都有特定的,如QMouseEvent、QKeyEvent等,它们继承自QEvent,并增加了特定于事件的函数。 在Qt中,事件处理的核心是QObject的事件处理函数(event())和事件过滤器(eventFilter)。我们可以通过重写这些函数来处理或过滤事件。 下面我将分步骤解释Qt的输入事件处理机制: ### 1. **事件型** Qt中的事件型通过`QEvent::Type`枚举定义。输入事件主要包括: - `QEvent::KeyPress` 和 `QEvent::KeyRelease`:键盘事件,由`QKeyEvent`表示。 - `QEvent::MouseButtonPress`, `QEvent::MouseButtonRelease`, `QEvent::MouseMove`:鼠标事件,由`QMouseEvent`表示。 - 触摸事件、手势事件等。 ### 2. **事件处理流程** 在Qt中,事件处理遵循以下流程: 1. **事件产生**:由操作系统或Qt内部产生。 2. **事件派发**:通过`QCoreApplication::notify()`将事件发送到目标对象(通常是QWidget)。 3. **事件处理**:目标对象通过`event()`函数接收事件,然后根据事件型调用特定的事件处理函数(如`keyPressEvent()`, `mousePressEvent()`等)。 ### 3. **自定义事件处理** 我们可以通过以下方式自定义事件处理: - **重写特定事件处理函数**:例如,在自定义的QWidget子中重写`keyPressEvent()`来处理键盘按下事件。 - **重写event()函数**:通过重写`event()`函数,可以在事件被分发到特定事件处理函数之前拦截所有事件。 ```cpp class MyWidget : public QWidget { protected: bool event(QEvent *event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); // 处理按键事件 if (keyEvent->key() == Qt::Key_A) { qDebug() << "Key 'A' pressed"; return true; // 事件已处理 } } // 其他事件交给基处理 return QWidget::event(event); } void keyPressEvent(QKeyEvent *event) override { // 也可以在这里处理 qDebug() << "Key pressed in keyPressEvent:" << event->key(); } }; ``` ### 4. **事件过滤器** 事件过滤器允许一个对象监视另一个对象的事件。这在无法继承目标时非常有用。 ```cpp // 在某个对象(如主窗口)中安装事件过滤器 ui->targetWidget->installEventFilter(this); // 重写eventFilter函数 bool MainWindow::eventFilter(QObject *watched, QEvent *event) { if (watched == ui->targetWidget) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Escape) { // 过滤掉ESC键 return true; } } } // 其他事件继续传递 return false; } ``` ### 5. **发送自定义事件** 我们可以创建自定义事件并发送到对象。自定义事件需要继承`QEvent`,并定义一个唯一的事件型(大于`QEvent::User`)。 ```cpp // 自定义事件型 const QEvent::Type MyEventType = static_cast<QEvent::Type>(QEvent::User + 1); // 自定义事件 class MyEvent : public QEvent { public: MyEvent(const QString &message) : QEvent(MyEventType), m_message(message) {} QString message() const { return m_message; } private: QString m_message; }; // 发送自定义事件 QApplication::postEvent(targetObject, new MyEvent("Hello")); ``` ### 6. **输入事件与设备过滤** 在Linux下,我们可以通过事件对象的设备信息来过滤特定设备(如触摸屏)的事件。在Qt5.0及以上版本,`QInputEvent`及其子(如`QMouseEvent`)提供了`device()`函数,返回一个`QInputDevice`对象,我们可以通过该对象获取设备信息。 ```cpp void MyWidget::mousePressEvent(QMouseEvent *event) { if (event->device()->name().contains("TouchScreen")) { // 忽略触摸屏的鼠标事件 return; } // 处理其他鼠标事件 } ``` ### 7. **事件循环与异步处理** Qt的事件循环由`QCoreApplication::exec()`启动。事件循环负责等待事件并将其分发给目标对象。我们可以使用`QCoreApplication::processEvents()`在长时间操作中处理事件以避免界面冻结。 ### 数学表达 事件处理过程可以视为一个映射函数: $$ \text{处理函数} : E \times O \rightarrow \{ \text{true}, \text{false} \} $$ 其中$E$是事件集合,$O$是对象集合。返回`true`表示事件已被处理,不再传递;返回`false`表示事件继续传递。 ### 注意事项 - 在事件处理函数中避免耗时操作,否则会阻塞事件循环。 - 跨平台考虑:不同平台下事件可能有差异。 - 内存管理:自定义事件需要动态创建,由Qt的事件系统自动删除。 §§相关问题§§ 1. 如何防止在事件处理函数中阻塞事件循环?[^1] 2. Qt事件处理与信号槽机制有何区别和联系?[^2] 3. 在Qt中如何处理多点触控事件?[^3] 4. 如何模拟键盘或鼠标事件进行自动化测试?[^1] 5. 自定义事件与信号槽在性能上有何差异?[^3] [^1]: 引用自用户提供的设备事件测试和权限问题说明 [^2]: 引用自用户提供的X11事件监控讨论 [^3]: 引用自用户提供的Qt项目结构参考</think>### Qt 输入事件处理机制:QEvent 与 QInputEvent 详解 在 Qt 框架中,输入事件处理基于 **事件驱动模型**,其核心组件包括 `QEvent` 基和其子 `QInputEvent`。以下是完整的处理机制: #### 1. **事件层级结构** ```mermaid classDiagram QEvent <|-- QInputEvent QInputEvent <|-- QKeyEvent QInputEvent <|-- QMouseEvent QInputEvent <|-- QWheelEvent QInputEvent <|-- QTouchEvent class QEvent { +Type type() const +bool isAccepted() const +void accept() +void ignore() } class QInputEvent { +QPointF globalPosition() const +ulong timestamp() const +QInputDevice* device() const } ``` #### 2. **核心处理流程** 1. **事件产生**:输入设备(键盘/鼠标)触发系统事件 2. **事件封装**:Qt 将系统事件封装为 `QInputEvent` 子对象 3. **事件分发**:通过 `QCoreApplication::notify()` 发送到目标对象 4. **事件处理**:目标对象通过重写事件处理函数响应 #### 3. **关键事件型与处理函数** | 事件型 (QEvent::Type) | 处理函数 | 事件 | |-------------------------|--------------------------|---------------| | `KeyPress`/`KeyRelease` | `keyPressEvent()` | `QKeyEvent` | | `MouseButtonPress` | `mousePressEvent()` | `QMouseEvent` | | `MouseMove` | `mouseMoveEvent()` | `QMouseEvent` | | `Wheel` | `wheelEvent()` | `QWheelEvent` | | `TouchBegin`/`Update` | `touchEvent()` | `QTouchEvent` | #### 4. **自定义事件处理(3种方式)** **方式1:重写控件事件函数** ```cpp class CustomWidget : public QWidget { protected: void keyPressEvent(QKeyEvent *event) override { if (event->key() == Qt::Key_Escape) { qDebug() << "ESC blocked"; // 拦截ESC键 event->accept(); // 标记事件已处理[^2] } else { QWidget::keyPressEvent(event); // 传递其他按键 } } }; ``` **方式2:安装事件过滤器** ```cpp // 在父对象中监控子控件 ui->lineEdit->installEventFilter(this); bool ParentWidget::eventFilter(QObject *watched, QEvent *event) { if (watched == ui->lineEdit && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Enter) return true; // 阻止回车键[^1] } return false; // 其他事件继续传递 } ``` **方式3:创建自定义事件** ```cpp // 定义自定义事件型 (值 > QEvent::User) const QEvent::Type CustomInputEvent = static_cast<QEvent::Type>(QEvent::User + 1); // 派发自定义事件 QApplication::postEvent(targetObj, new QEvent(CustomInputEvent)); // 处理自定义事件 bool MyObject::event(QEvent *event) { if (event->type() == CustomInputEvent) { handleCustomEvent(); return true; } return QObject::event(event); } ``` #### 5. **输入设备识别(Linux特有)** 通过 `QInputEvent::device()` 获取设备信息: ```cpp void MyWidget::mousePressEvent(QMouseEvent *event) { qDebug() << "Device:" << event->device()->name(); // 输出如 "USB Optical Mouse" // 屏蔽特定设备 if (event->device()->name().contains("TouchPad")) { event->ignore(); // 忽略触摸板事件[^1] } } ``` #### 6. **事件传播机制** - **事件接受**:调用 `event->accept()` 停止传播 - **事件忽略**:调用 `event->ignore()` 传递给父对象 - **传播路径**:子控件 → 父控件 → 顶层窗口 #### 7. **事件与信号槽的区别** | 特性 | 事件 (QEvent) | 信号槽 (Signal/Slot) | |--------------|-----------------------------|---------------------------| | 处理层级 | 底层输入处理 | 高层业务逻辑 | | 传播方式 | 冒泡传播 | 直接连接 | | 性能 | 更高效率 (直接处理) | 略低 (需查找连接) | | 典型应用场景 | 原始输入处理、设备过滤 | 对象间通信、状态更新 | #### 8. **数学表达:事件处理模型** 事件处理流程可形式化为: $$ \text{处理结果} = f_{\text{filter}} \circ f_{\text{handler}} (E) $$ 其中: - $E$ 是输入事件元组 $(type, device, position, state)$ - $f_{\text{filter}}$ 是事件过滤函数 - $f_{\text{handler}}$ 是事件处理函数 当事件被接受时: $$ \text{accept}(E) \Rightarrow \forall P \in \text{ParentChain}, P \text{ 不接收 } E $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值