QT事件系统
# 06.QT事件系统
- 6.1 事件系统
- 6.1.1 事件处理
- 6.1.2 自定义事件
- 6.1.3 事件系统
- 6.2 事件循环
- 6.2.1 事件循环流程
- 6.2.2 核心原理
- 6.2.3 事件队列
- 6.2.4 处理事件
- 6.2.5 处理任务
- 6.2 QT事件处理
- 6.2.2 事件处理函数
- 6.2.3 事件过滤器
- 6.2.4 自定义事件
- 6.2.5 定时器事件
- 6.3 QEvent
- 6.3.1 QEvent概述
- 6.3.2 常见QEvent子类
- 6.4 事件处理
- 6.4.1 重写事件函数
- 6.4.2 重写event()函数
- 6.4.3 安装事件过滤器
- 6.4.4 事件传播
# 6.1 事件系统
Qt 的事件处理机制是其核心功能之一,用于处理用户输入、窗口事件、定时器事件等。
Qt 的事件系统基于事件循环(Event Loop)和事件过滤器(Event Filter),开发者可以通过重写事件处理函数或安装事件过滤器来拦截和处理事件。
# 6.1.1 事件处理
- QEvent:事件基类
- QCoreApplication:事件循环管理
- QEventLoop:事件循环
- QAbstractEventDispatcher:事件分发器抽象
# 6.1.2 自定义事件
- 自定义事件类型
- 事件过滤器(eventFilter)
- 发送事件(sendEvent/postEvent)
# 6.1.3 事件系统
功能:处理用户输入、定时器事件、自定义事件等。核心类:
QEvent:所有事件的基类。QCoreApplication:管理事件循环。QTimer:定时器事件。QKeyEvent、QMouseEvent:键盘和鼠标事件。
# 6.2 事件循环
# 6.2.1 事件循环流程
Qt 应用程序的核心是事件循环,它负责接收和分发事件。事件循环由 QCoreApplication::exec() 启动。
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
qDebug() << "Event loop started";
return app.exec(); // 启动事件循环
}
2
3
4
5
6
7
8
事件循环工作流程:
- 等待事件: 监听系统事件(鼠标、键盘、定时器、网络等)
- 分发事件: 将事件分发给相应的对象处理
- 处理事件: 调用相应的事件处理函数
- 更新界面: 重绘需要更新的界面元素
- 循环继续: 回到步骤1,直到应用退出
# 6.2.2 核心原理
每个 Qt 应用至少有一个事件循环(在主线程中,由 QApplication::exec() 启动)。它不停地做一件事:
- 检查事件队列:是否有新事件到来?(如鼠标点击、键盘输入、定时器超时、网络数据到达、重绘请求等)。
- 处理事件:将事件分发给相应的目标对象(
QObject)。 - 处理任务:处理事件循环本身需要执行的任务,比如处理排队的信号槽调用(Qt 的默认连接方式,
Qt::AutoConnection,在跨线程时是异步的,但在同一线程内是同步的,其实相当于直接函数调用)。
while (isRunning) {
// 1. 检查事件队列,处理事件
while (eventQueue.hasEvents()) {
processNextEvent();
}
// 2. 处理其他任务(如信号槽调用)
processPendingTasks();
// 3. 进入休眠,直到有事件到来或定时器触发
waitForMoreEvents();
}
2
3
4
5
6
7
8
9
10
11
12
事件循环处理事件的流程如下:
- 事件产生:事件由操作系统、硬件或应用程序内部产生。
- 事件投递:事件被放入事件队列(通过 postEvent()或系统事件投递)。
- 事件分发:事件循环从队列中取出事件,并分发给目标对象(QObject)。
- 事件处理:目标对象的 event()方法被调用,进而调用特定的事件处理函数(如 mousePressEvent()、keyPressEvent()等)。
Qt 事件循环的核心思想是事件驱动编程模型,其基本工作流程如下:
+----------------+ +----------------+ +----------------+
| 事件生产者 | | 事件队列 | | 事件消费者 |
| (硬件/系统/应用) |---->| (FIFO缓冲区) |---->| (QObject子类) |
+----------------+ +----------------+ +----------------+
| | |
| 生成事件 | 存储/排序 | 处理事件
| (鼠标点击/网络数据等) | | (重绘/业务逻辑)
2
3
4
5
6
7
核心原则:
- 非阻塞等待:在没有事件时进入高效休眠状态
- 事件优先级:不同类型事件有不同处理优先级
- 线程隔离:每个线程有独立的事件队列和循环
- 统一调度:所有异步操作最终都转化为事件处理
# 6.2.3 事件队列
事件队列的组成,事件队列(Event Queue)是一个先进先出(FIFO)的数据结构,用于存储待处理的事件。事件包括:
- 用户输入事件:鼠标点击、键盘输入等。
- 系统事件:窗口重绘、定时器超时、网络数据到达等。
- 自定义事件:用户通过 QCoreApplication::postEvent()发送的事件。
多级优先级队列,Qt 使用复杂的数据结构管理事件队列:
// 伪代码表示事件队列结构
class QEventLoop {
QQueue<QEvent*> highPriorityEvents; // 高优先级事件(重绘、定时器)
QQueue<QEvent*> normalEvents; // 普通事件(用户输入)
QQueue<QEvent*> lowPriorityEvents; // 低优先级事件(空闲任务)
QQueue<DeferredDeleteEvent> deleteLaterEvents; // 延迟删除事件
};
2
3
4
5
6
7
事件处理优先级(从高到低):
- 定时器事件:保证精确时间触发
- 重绘事件:避免界面卡顿
- 输入事件:响应用户交互
- 网络事件:处理I/O操作
- 空闲事件:执行低优先级任务
事件循环核心算法
bool QEventLoop::processEvents() {
while (!exitRequested) {
// 步骤1:处理高优先级事件
while (hasHighPriorityEvents()) {
QEvent *e = dequeueHighPriorityEvent();
dispatchEvent(e); // 分发到目标对象
}
// 步骤2:处理普通事件
if (hasEvents()) {
QEvent *e = dequeueEvent();
dispatchEvent(e);
continue; // 返回处理高优先级事件
}
// 步骤3:处理延迟删除
processDeferredDeletion();
// 步骤4:处理空闲任务
if (hasIdleTasks()) {
processIdleTasks();
}
// 步骤5:进入高效等待
if (noEventsPending) {
waitForEvents(timeout); // 使用epoll/kqueue/select等系统调用
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 6.2.4 处理事件
事件循环在每次迭代中检查事件队列:
- 非阻塞检查:如果有事件,立即处理。
- 阻塞等待:如果队列为空,事件循环会进入休眠状态,直到有事件到来。唤醒条件包括:
- 新事件到达(如用户输入)。
- 定时器超时。
- 外部唤醒(如调用 QCoreApplication::wakeUp())。
# 6.2.5 处理任务
# 6.2 QT事件处理
# 6.2.2 事件处理函数
Qt 中的事件处理函数是 QObject 的成员函数,可以通过重写这些函数来处理特定事件。
1.常用事件处理函数
mousePressEvent(QMouseEvent *):处理鼠标按下事件。mouseMoveEvent(QMouseEvent *):处理鼠标移动事件。keyPressEvent(QKeyEvent *):处理键盘按下事件。paintEvent(QPaintEvent *):处理绘制事件。resizeEvent(QResizeEvent *):处理窗口大小调整事件。closeEvent(QCloseEvent *):处理窗口关闭事件。
2.示例:重写事件处理函数
#include <QWidget>
#include <QMouseEvent>
#include <QDebug>
class MyWidget : public QWidget {
protected:
void mousePressEvent(QMouseEvent *event) override {
qDebug() << "Mouse pressed at:" << event->pos();
}
void keyPressEvent(QKeyEvent *event) override {
qDebug() << "Key pressed:" << event->text();
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget widget;
widget.resize(200, 200);
widget.show();
return app.exec();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 6.2.3 事件过滤器
事件过滤器允许一个对象拦截并处理另一个对象的事件。
1.安装事件过滤器
#include <QApplication>
#include <QWidget>
#include <QDebug>
class EventFilter : public QObject {
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
if (event->type() == QEvent::MouseButtonPress) {
qDebug() << "Mouse pressed in:" << obj->objectName();
return true; // 事件已被处理
}
return QObject::eventFilter(obj, event);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget widget;
widget.setObjectName("MainWidget");
EventFilter filter;
widget.installEventFilter(&filter); // 安装事件过滤器
widget.resize(200, 200);
widget.show();
return app.exec();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 6.2.4 自定义事件
Qt 允许开发者创建和发送自定义事件。
1.定义自定义事件
#include <QEvent>
const QEvent::Type MyCustomEventType = static_cast<QEvent::Type>(QEvent::User + 1);
class MyCustomEvent : public QEvent {
public:
MyCustomEvent(const QString &message)
: QEvent(MyCustomEventType), m_message(message) {}
QString message() const { return m_message; }
private:
QString m_message;
};
2
3
4
5
6
7
8
9
10
11
12
2.发送自定义事件
#include <QApplication>
#include <QWidget>
#include <QDebug>
class MyWidget : public QWidget {
protected:
void customEvent(QEvent *event) override {
if (event->type() == MyCustomEventType) {
MyCustomEvent *customEvent = static_cast<MyCustomEvent *>(event);
qDebug() << "Custom event received:" << customEvent->message();
}
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget widget;
widget.resize(200, 200);
widget.show();
// 发送自定义事件
MyCustomEvent event("Hello, Custom Event!");
QApplication::postEvent(&widget, &event);
return app.exec();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 6.2.5 定时器事件
# 6.3 QEvent
在 Qt 中,QEvent 是所有事件类的基类。Qt 的事件系统用于处理各种用户交互、系统事件和应用程序内部事件。
每个事件都是一个 QEvent 或其子类的实例,Qt 通过事件循环将这些事件分发给相应的对象(如窗口部件)进行处理。
# 6.3.1 QEvent概述
QEvent 是 Qt 事件系统的核心类,所有事件都继承自 QEvent。
- 事件可以是用户输入(如鼠标点击、键盘按键)、系统事件(如定时器事件、窗口事件)或自定义事件。
- 事件通过
QObject::event()或特定的事件处理函数(如mousePressEvent())进行处理。
# 6.3.2 常见QEvent子类
Qt 提供了许多内置的事件类型,以下是一些常见的 QEvent 子类:
| 事件类型 | 描述 |
|---|---|
QMouseEvent | 鼠标事件(点击、移动、释放等)。 |
QKeyEvent | 键盘事件(按键按下、释放)。 |
QResizeEvent | 窗口或部件大小改变事件。 |
QPaintEvent | 绘制事件,用于重绘部件。 |
QTimerEvent | 定时器事件,用于处理定时器超时。 |
QCloseEvent | 窗口关闭事件。 |
QFocusEvent | 焦点事件(获得焦点、失去焦点)。 |
QWheelEvent | 鼠标滚轮事件。 |
QDropEvent | 拖放事件。 |
QDragEnterEvent | 拖拽进入事件。 |
QHoverEvent | 鼠标悬停事件。 |
QContextMenuEvent | 上下文菜单事件(右键菜单)。 |
QInputMethodEvent | 输入法事件。 |
QActionEvent | 与 QAction 相关的事件。 |
QCustomEvent | 自定义事件(已弃用,推荐使用 QEvent 的子类)。 |
# 6.4 事件处理
Qt 提供了多种方式来处理事件:
# 6.4.1 重写事件函数
在自定义的 QWidget 或 QObject 子类中,重写特定的事件处理函数。例如:
class MyWidget : public QWidget {
protected:
void mousePressEvent(QMouseEvent *event) override {
qDebug() << "Mouse pressed at:" << event->pos();
}
void keyPressEvent(QKeyEvent *event) override {
qDebug() << "Key pressed:" << event->text();
}
};
2
3
4
5
6
7
8
9
10
# 6.4.2 重写event()函数
通过重写 QObject::event() 函数,可以处理所有事件:
class MyWidget : public QWidget {
protected:
bool event(QEvent *event) override {
if (event->type() == QEvent::MouseButtonPress) {
qDebug() << "Mouse press event detected!";
return true; // 事件已处理
}
return QWidget::event(event); // 其他事件交给父类处理
}
};
2
3
4
5
6
7
8
9
10
# 6.4.3 安装事件过滤器
通过 QObject::installEventFilter(),可以监听其他对象的事件:
class MyFilter : public QObject {
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
if (event->type() == QEvent::KeyPress) {
qDebug() << "Key press event filtered!";
return true; // 事件已处理
}
return QObject::eventFilter(obj, event); // 其他事件交给父类处理
}
};
// 使用事件过滤器
MyFilter filter;
myWidget->installEventFilter(&filter);
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.4.4 事件传播
- 事件传播:事件会从子对象向父对象传播,直到被处理或到达顶层对象。
- 事件接受与忽略:通过
QEvent::accept()和QEvent::ignore()可以控制事件是否继续传播。