Qt系统相关

一、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; // 放行
}
相关推荐
redaijufeng1 小时前
C/C++程序从编译到链接的过程
c语言·开发语言·c++
木子墨5161 小时前
系统设计面试 | 实现一个限流器:滑动窗口 → 令牌桶 → 漏桶
java·开发语言·数据结构·数据库·面试·职场和发展
Byte Wizard1 小时前
C语言指针深入浅出6
c语言·开发语言
知识分享小能手2 小时前
R语言入门学习教程,从入门到精通,R语言数据处理与清洗 (9)
开发语言·学习·r语言
计算机安禾2 小时前
【c++面向对象编程】第19篇:多继承与菱形继承(二):虚拟继承的内存模型与复杂性
开发语言·c++
思麟呀2 小时前
在C++基础上理解CSharp-1
开发语言·c++·c#
星河漫步Lu2 小时前
QT6中五步完成Android的环境配置
android·qt
一念春风2 小时前
QwenPaw(替代小龙虾)大模型
开发语言·php
小短腿的代码世界2 小时前
Qt状态机框架深度解析:从状态图到事件驱动闭环
开发语言·qt