一、Qt事件(Event)
定义:事件(Event) 是应用程序 内部状态改变 或 外部用户操作 的统称,在 Qt 中以 QEvent对象 的形式存在。
特点:
- **面向对象:**所有事件都继承自 QEvent
- **异步驱动:**由系统或 Qt 自动发出,程序被动接收
- **可被拦截:**可在传递过程中被处理或忽略
- **携带信息:**包含发生时间、位置、类型等数据
- **分发有序:**通过事件循环(Event Loop)统一分发
事件的种类:
| 事件名称 | 描述 | 对应 QEvent 子类 |
|---|---|---|
| 鼠标事件 | 鼠标按下、释放、移动、双击 | **QMouseEvent** |
| 滚轮事件 | 鼠标滚轮滚动 | **QWheelEvent** |
| 键盘事件 | 按键按下、释放 | **QKeyEvent** |
| 定时器事件 | 定时时间到达 | **QTimerEvent** |
| 进入离开事件 | 鼠标进入或离开控件区域 | QEnterEvent / QEvent |
| 悬停事件 | 鼠标悬停在控件上 | **QHoverEvent** |
| 绘屏事件 | 重绘屏幕的某些部分 | **QPaintEvent** |
| 显示隐藏事件 | 窗口或控件的显示和隐藏 | QShowEvent / **QHideEvent** |
| 移动事件 | 窗口位置的变化 | **QMoveEvent** |
| 窗口事件 | 窗口状态改变(激活/非激活) | **QWindowStateChangeEvent** |
| 大小改变事件 | 窗口大小改变 | **QResizeEvent** |
| 焦点事件 | 键盘焦点进入或离开 | **QFocusEvent** |
| 拖拽事件 | 拖拽进入、移动、放下 | QDragEnterEvent / **QDropEvent** |
| 上下文菜单事件 | 右键点击触发菜单 | **QContextMenuEvent** |
| 关闭事件 | 窗口被关闭 | **QCloseEvent** |
1、鼠标事件(Mouse Events)
- 鼠标事件是 GUI 开发中最频繁使用的事件之一,用于描述鼠标指针与控件的交互行为。
1️⃣ 常见鼠标事件类型
| 事件名称 | 对应 QEvent 子类 | 触发时机 |
|---|---|---|
| 鼠标按下 | QMouseEvent |
按下鼠标按键 |
| 鼠标释放 | QMouseEvent |
松开鼠标按键 |
| 鼠标移动 | QMouseEvent |
鼠标在控件上移动 |
| 鼠标双击 | QMouseEvent |
快速连续两次单击 |
| 鼠标滚轮 | QWheelEvent |
滚动鼠标滚轮 |
| 鼠标进入 | QEnterEvent |
鼠标光标移入控件区域 |
| 鼠标离开 | QEvent::Leave |
鼠标光标移出控件区域 |
2️⃣ 核心处理函数
在 QWidget及其子类中,通过重写以下函数处理鼠标事件:
cpp
// 鼠标按下
void mousePressEvent(QMouseEvent *event);
// 鼠标释放
void mouseReleaseEvent(QMouseEvent *event);
// 鼠标移动
void mouseMoveEvent(QMouseEvent *event);
// 鼠标双击
void mouseDoubleClickEvent(QMouseEvent *event);
// 滚轮滚动
void wheelEvent(QWheelEvent *event);
3️⃣ QMouseEvent 关键 API
| API | 说明 |
|---|---|
event->button() |
获取触发事件的按键(左/右/中键) |
event->buttons() |
获取当前所有按下的按键(支持组合) |
event->pos() |
获取相对于当前控件的坐标 |
event->globalPos() |
获取相对于屏幕的绝对坐标 |
event->type() |
获取事件类型(按下/释放/移动) |
4️⃣简单运用
cpp
//获取鼠标的实时位置
void Widget::mouseMoveEvent(QMouseEvent *event)
{
QString s="(";
s+=std::to_string(event->pos().x());
s+=",";
s+=std::to_string(event->pos().y());
s+=")";
ui->label->setText(s);
//开启鼠标追踪,默认情况下mouseMoveEvent只有鼠标点击时才会触发,当开启了鼠标追踪就不用依赖鼠标点击
setMouseTracking(true);
}

2、键盘事件(Key Events)
- 键盘事件用于处理按键输入,是所有需要快捷键、文本输入或游戏控制的 GUI 程序的基础。
- 注意 :控件必须获得焦点 (
setFocus())才能接收键盘事件。
1️⃣ 常见键盘事件类型
| 事件名称 | 对应 QEvent 子类 | 触发时机 |
|---|---|---|
| 按键按下 | QKeyEvent |
键盘按键被按下 |
| 按键释放 | QKeyEvent |
键盘按键被松开 |
| 按键重复 | QKeyEvent |
长按按键时的自动重复触发 |
2️⃣ 核心处理函数
cpp
// 按键按下
void keyPressEvent(QKeyEvent *event);
// 按键释放
void keyReleaseEvent(QKeyEvent *event);
3️⃣ QKeyEvent 关键 API
| API | 说明 |
|---|---|
event->key() |
获取按键的虚拟键值 (如 Qt::Key_Space) |
event->text() |
获取按键生成的实际字符 (如 "A") |
event->modifiers() |
获取修饰键状态(Ctrl / Shift / Alt) |
event->isAutoRepeat() |
判断是否是长按导致的自动重复 |
4️⃣简单运用
cpp
//记录按键按下的方向
void Widget::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Up:
qDebug() << "向上";
break;
case Qt::Key_Down:
qDebug() << "向下";
break;
case Qt::Key_Left:
qDebug() << "向左";
break;
case Qt::Key_Right:
qDebug() << "向右";
break;
default:
QWidget::keyPressEvent(event);
}
}

3、定时事件(Timer Events)
- 定时事件用于在特定时间间隔触发逻辑,常用于动画、轮询、心跳检测等场景。
- Qt 提供了两种定时器机制:QTimer(推荐) 和 QTimerEvent(底层)。
1️⃣QTimer 方式(最常用)
- 利用信号槽机制,代码最简洁,安全性最高。
核心API:
| API | 说明 |
|---|---|
start(int msec) |
启动定时器(毫秒) |
stop() |
停止定时器 |
timeout() |
时间到的信号 |
setSingleShot(true) |
只触发一次 |
2️⃣QTimerEvent 方式(底层)
- 继承自
QObject,通过重写timerEvent处理。
核心API:
| API | 说明 |
|---|---|
startTimer(int msec) |
启动定时器,返回 TimerId |
killTimer(int id) |
根据 ID 停止定时器 |
timerEvent(QTimerEvent *event) |
定时器回调函数 |
3️⃣常见坑位提醒
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 定时器不触发 | 没有启动事件循环 | 确保调用了 exec()或程序未退出 |
| 内存泄漏 | 忘记 killTimer |
使用 QTimer(自动回收) |
| 界面卡顿 | 超时函数中执行耗时操作 | 将耗时逻辑移到子线程 |
| 精度不准 | 系统负载过高 | 不要依赖定时器做高精度计时 |
4️⃣简单运用
- QTimer 方式
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Widget::onTimeout);
timer->start(1000); // 每 1000ms (1秒) 触发一次
}
//加法计时器
void Widget::onTimeout()
{
static int count = 0;
qDebug() << "定时器触发:" << ++count << "秒";
}

- QTimerEvent 方式
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 启动定时器
timerId = startTimer(1000); // 1秒
}
//加法计时器
void Widget::timerEvent(QTimerEvent *event)
{
if (event->timerId() == timerId)
{
static int count = 0;
qDebug() << "定时器触发:" << ++count << "秒";
}
}

二、事件分发器**(Event Dispatcher)**
- 在 Qt 中,事件分发器 是连接 事件产生 与 事件处理 之间的桥梁。
- 它决定了事件由谁来接收、谁来处理、以及是否可以被拦截。
1、事件分发器的三个层级
1️⃣ QApplication::notify()(最顶层)
- 这是所有事件的起点。
cpp
bool QApplication::notify(QObject *receiver, QEvent *event);
特点:
- 负责把事件发送给指定的接收者
- 可以在这里全局拦截所有事件
- 极少重写(风险大)
2️⃣ QObject::event()(核心分发器)
- 每个
QObject都有自己的event()函数。
cpp
bool Widget::event(QEvent *event)
| 行为 | 说明 |
|---|---|
return true |
事件已处理,停止分发 |
return false |
继续交给父类处理 |
3️⃣ 具体事件处理函数(最终执行者)
cpp
void mousePressEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *);
void timerEvent(QTimerEvent *);
4️⃣简单运用
cpp
//鼠标点击事件
void mouseMoveEvent(QMouseEvent *event);
//通过事件分发器拦截点击事件
bool event(QEvent* ev);
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
qDebug()<<"鼠标左键按下!";
}
}
bool Widget::event(QEvent *ev)
{
if(ev->type()==QEvent::MouseButtonPress)
{
qDebug()<<"event中鼠标左键按下!";
return true;//返回true不在向下分发事件
}
//其他事件交给父类处理
return QWidget::event(ev);
}

三、事件过滤器(Event Filter)
事件过滤器 = 在目标对象收到事件之前,先进行预处理。
特点:
- 不需要子类化控件
- 可以监听任意
QObject - 常用于 统一管理、权限控制、行为增强
1️⃣核心 API
cpp
//安装事件过滤器
watchedObject->installEventFilter(this);
//重写事件过滤函数,watched是监听的对象
bool eventFilter(QObject *watched, QEvent *event) override;
2️⃣简单运用
cpp
#include "Widget.h"
#include <QKeyEvent>
Widget::Widget(QWidget *parent) : QWidget(parent) {
edit = new QLineEdit(this);
edit->setGeometry(50, 50, 200, 30);
// 给 edit 安装事件过滤器
edit->installEventFilter(this);
}
bool Widget::eventFilter(QObject *watched, QEvent *event) {
if (watched == edit && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
int key = keyEvent->key();
// 只允许数字
if (key < Qt::Key_0 || key > Qt::Key_9) {
qDebug() << "非数字键被拦截";
return true; // 拦截
}
}
return false; // 放行
}
