当前位置: 首页 > news >正文

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件

事件 是一个描述应用程序中、发生的某些事情的对象。

在 Qt 中,所有事件都继承自 QEvent ,并且每个事件都有特定的标识符,如:Qt::MouseButtonPress 代表鼠标按下事件。

每个事件对象包含该事件的所有相关信息,如:鼠标事件包含鼠标的坐标、按下的按钮等信息。

2. 事件处理器

事件处理器 是用于处理特定类型事件的成员函数,通常以 event 结尾,如:mousePressEvent 、enterEvent 等。

事件处理器定义了当某个事件发生时,应执行的操作。

事件处理器可以分为两类:

  • 预定义事件处理器:由 Qt 提供的标准事件处理函数,可以通过重写它们以实现自定义行为。
class SessionFriendItem : public QWidget
{Q_OBJECT
public:SessionFriendItem(QWidget* owner, const QIcon& avatar, const QString& name, const QString& text): owner(owner), selected(false){// 1. 设置基本属性和样式this->setFixedHeight(64);this->setStyleSheet("QWidget { background-color: rgb(236, 233, 231); }");// 2. 创建网格布局QGridLayout* layout = new QGridLayout();layout->setContentMargins(0, 0, 0, 0);layout->setVerticalSpacing(0); // 设置竖直方向间距layout->setHorizontalSpacing(0); // 设置水平方向间距this->setLayout(layout);// 3. 创建头像QPushButton avatar_btn = new QPushButton();avatar_btn->setFixedSize(QSize(46, 46));avatar_btn->setIconSize(QSize(46, 46));avatar_btn->setIcon(avatar);avatar_btn->setStyleSheet("QPushButton { border: none; background-color: transparent; }");layout->addWidget(avatar_btn, 0, 0, 2, 2);// 4. 创建昵称QLabel* name_label = new QLabel();name_label->setText(name);name_label->setFixedHeight(30);name_label->setStyleSheet("QLabel { font-size: 14px; }");layout->addWidget(name_label, 0, 2, 1, 6);// 5. 添加预览消息QLabel* msg_label = new QLabel();msg_label->setText(text);msg_label->setFixedHeight(25);msg_label->setStyleSheet("QLabel { font-size: 12px; }");layout->addWidget(msg_label, 1, 2, 1, 6);}void mousePressEvent(QMouseEvent* event) override{// 1. 恢复兄弟组件的 rgbQObjectList* children = this->parent()->children();for (QObject* child : children){if (child->isWidgetType() == false) continue;SessionFriendItem* temp = dynamic_cast<SessionFriendItem*>(child);if (temp->selected == true){temp->selected = false;temp->setStyleSheet("QWidget { background-color: rgb(236, 233, 231); }");}}// 2. 设置当前组件的 rgbthis->selected = true;this->setStyleSheet("QWidget { background-color: rgb(200, 199, 198); }");}void enterEvent(QEnterEvent* event) override{// 当前组件被点击,则不处理if (selected == true) return; this->setStyleSheet("QWidget { background-color: rgb(222, 220, 218); }");}void leaveEvent(QEvent* event) override{if (selected == true) return;this->setStyleSheet("QWidget { background-color: rgb(236, 233, 231); }");}
private:QWidget* owner;bool selected;
};

  • 自定义事件处理器:处理一些特殊类型的事件,可以通过事件过滤器或子类化 QObject 来实现。
3. 事件过滤器

在 Qt 中,事件过滤器(eventFilter)提供了一种机制,允许一个对象 监视并处理 另一个对象的事件

3.1 基本概念

事件过滤器允许拦截发送给某个对象的所有事件,并在这些事件被该对象处理之前,决定如何处理它们。

步骤:

  • 安装事件过滤器:通过调用 installEventFilter() 方法,将一个对象设置为另一个对象的事件过滤器。
  • 重写 eventFilter() 函数:在作为事件过滤器的对象中,重写 bool eventFilter(QObject* obj, QEvent* event) 函数,来定义具体的事件处理逻辑。
3.2 工作原理

QMainWindow 不能直接设置布局,需要通过中央部件来管理布局。

this->setCentralWidget()

// mainwindow.h
class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();bool eventFilter(QObject* object, QEvent* event) override;QWidget* mainWidget;QPushButton* button;private:Ui::MainWindow *ui;
};// mainwindow.cpp
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);mainWidget = new QWidget(this);this->setCentralWidget(mainWidget);QVBoxLayout* layout = new QVBoxLayout();mainWidget->setLayout(layout);button = new QPushButton();button->setText("点击");button->setFixedSize(QSize(50, 50));layout->addWidget(button);// 安装事件过滤器button->installEventFilter(this);
}bool MainWindow::eventFilter(QObject* object, QEvent* event)
{if (object == button){if (event->type() == QEvent::MouseButtonPress){qDebug() << "Button_Press";}else if (event->type() == QEvent::Enter){qDebug() << "Button_Enter";}else if (event->type() == QEvent::Leave){qDebug() << "Button_Leave";}// return false; // 允许事件继续传递return true;}// 交给其它事件处理器处理return QMainWindow::eventFilter(object, event);
}

鼠标进入按钮上方,鼠标点击按钮,鼠标离开按钮

installEventFilter 的作用目标
  • 事件过滤器的本质:当一个对象 A 调用 installEventFilter(B) ,意味着对象 B 会优先接收到对象 A 的事件,并可以通过 eventFilter() 方法拦截或处理这些事件。

  • 如果希望在事件滤波器 B 处理完事件后,仍然让目标对象 A 继续处理该事件,可以在事件滤波器逻辑的末尾 return false。这样,事件会继续按照正常的事件处理流程传递下去。

  • 自定义类 能够作为事件过滤器、并被目标对象设置,需要确保该类重载了 eventfilter() 方法;原生的 Qt 对象(如 QWidget)无法直接担任事件过滤器的角色,因为它们没有提供对 eventfilter() 的重载接口。

4. 事件系统

Qt 的事件系统基于事件驱动模型工作,其核心是通过事件队列(Event Queue)实现异步调用。

以下是其基本运作流程:

4.1 事件产生

当用户与应用程序进行交互,或系统内部发生某些变化,就会产生相应的事件。

所有事件均封装为 QEvent 的子类对象。

例如,用户按下鼠标左键,会产生一个 QMouseEvent 对象,该对象包含了关于鼠标点击的所有信息,包括点击的位置、按钮的状态等;

键盘按键的按下或释放会产生 QKeyEvent 对象。

4.2 事件传递
  • 对于同步事件
  1. 使用 QCoreApplication::sendEvent() 方法时,事件会被立即发送给接收者。

  2. 发送事件的线程会等待,直到事件被完全处理。

  • 对于异步事件
  1. 使用 QCoreApplication::postEvent() 方法时,生成的事件并非被立即处理,而是被放入目标对象所属线程的事件队列中,等待调度。

  2. QCoreApplication::exec() 启动的主事件循环会从队列中取出事件进行处理(非阻塞),并通过 QCoreApplication::notify() 方法来分发该事件到目标对象(事件通知),确保每个事件都能被正确地发生给它的接收者。

  3. 在事件被传递给目标对象之前,如果有安装事件过滤器,首先会调用这些过滤器的 eventFilter() 方法;如果该事件没有被过滤器拦截,则继续传递给目标对象。

4.3 事件处理

通过重写 event() 方法,或特定的事件处理器(如 mousePressEvent() ),实现业务逻辑。

如果事件未被处理(如未重写 event() 或未调用基类实现),某些对象会向父对象传递(冒泡机制),直至顶层对象。

事件是否传递取决于事件类型和 accept() / ignore() 的标记。

QMouseEvent 默认 accept() ,QKeyEvent() 默认 ignore() ,QPaintEvent 仅在目标对象处理、不会传递。

void MainWindow::mousePressEvent(QMouseEvent* event)
{qDebug() << "button is pressed";event->accept(); // 标记事件已处理// event->ignore(); // 允许事件继续传递
}
4.4 事件结束

事件对象会在处理完成后,由 Qt 自动销毁;除非事件被通过 deleteLater() 标记为 deferred delete

相关文章:

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…...

DeepSeek相关技术整理

相关介绍 2024年12月26日&#xff0c;DeepSeek V3模型发布&#xff08;用更低的训练成本&#xff0c;训练出更好的效果&#xff09;671B参数&#xff0c;激活37B。2025年1月20日&#xff0c;DeepSeek-R1模型发布&#xff08;仅需少量标注数据&#xff08;高质量长cot&#xff…...

DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”

当算力博弈升级为网络战争&#xff1a;拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下&#xff0c;网络已然成为人类社会运转的关键基础设施&#xff0c;深刻融入经济、生活、政务等各个领域。从金融交易的实时清算&#xf…...

蓝桥杯之c++入门(二)【输入输出(上)】

目录 前言1&#xff0e;getchar和 putchar1.1 getchar()1.2 putchar() 2&#xff0e;scanf和 printf2.1 printf2.1.1基本用法2.1.2占位符2.1.3格式化输出2.1.3.1 限定宽度2.1.3.2 限定小数位数 2.2 scanf2.2.1基本用法2.2.2 占位符2.2.3 scanf的返回值 2.3练习练习1&#xff1a…...

消息队列应用示例MessageQueues-STM32CubeMX-FreeRTOS《嵌入式系统设计》P343-P347

消息队列 使用信号量、事件标志组和线标志进行任务同步时&#xff0c;只能提供同步的时刻信息&#xff0c;无法在任务之间进行数据传输。要实现任务间的数据传输&#xff0c;一般使用两种方式&#xff1a; 1. 全局变量 在 RTOS 中使用全局变量时&#xff0c;必须保证每个任务…...

算法题(55):用最少数量的箭引爆气球

审题&#xff1a; 本题需要我们找到最少需要的箭数&#xff0c;并返回 思路: 首先我们需要把本题描述的问题理解准确 &#xff08;1&#xff09;arrow从x轴任一点垂直射出 &#xff08;2&#xff09;一旦射出&#xff0c;无限前进 也就是说如果气球有公共区域&#xff08;交集&…...

谭浩强C语言程序设计(4) 8章(下)

1、输入三个字符串按照字母顺序从小到大输出 #include <cstdio> // 包含cstdio头文件&#xff0c;用于输入输出函数 #include <cstring> // 包含cstring头文件&#xff0c;用于字符串处理函数#define N 20 // 定义字符串的最大长度为20// 函数&#xff1a;…...

AlexNet论文代码阅读

论文标题&#xff1a; ImageNet Classification with Deep Convolutional Neural Networks 论文链接&#xff1a; https://volctracer.com/w/BX18q92F 代码链接&#xff1a; https://github.com/dansuh17/alexnet-pytorch 内容概述 训练了一个大型的深度卷积神经网络&#xf…...

62.病毒在封闭空间中的传播时间|Marscode AI刷题

1.题目 问题描述 在一个封闭的房间里摆满了座位&#xff0c;每个座位东西向和南北向都有固定 1 米的间隔。座位上坐满了人&#xff0c;坐着的人可能带了口罩&#xff0c;也可能没有带口罩。我们已经知道房间里的某个人已经感染了病毒&#xff0c;病毒的传播速度是每秒钟感染距…...

Elixir语言的安全开发

Elixir语言的安全开发 引言 在当今这个互联网高度发展的时代&#xff0c;软件的安全性变得越来越重要。随着网络攻击的增多&#xff0c;软件漏洞的频繁暴露&#xff0c;开发者面临着前所未有的安全挑战。Elixir&#xff0c;作为一种现代化的函数式编程语言&#xff0c;以其高…...

Rust 条件语句

Rust 条件语句 在编程语言中&#xff0c;条件语句是进行决策和实现分支逻辑的关键。Rust 语言作为一门系统编程语言&#xff0c;其条件语句的使用同样至关重要。本文将详细介绍 Rust 中的条件语句&#xff0c;包括其基本用法、常见场景以及如何避免常见错误。 基本用法 Rust…...

小红的合数寻找

A-小红的合数寻找_牛客周赛 Round 79 题目描述 小红拿到了一个正整数 x&#xff0c;她希望你在 [x,2x] 区间内找到一个合数&#xff0c;你能帮帮她吗&#xff1f; 一个数为合数&#xff0c;当且仅当这个数是大于1的整数&#xff0c;并且不是质数。 输入描述 在一行上输入一…...

使用等宽等频法进行数据特征离散化

在数据分析与处理的过程中,特征离散化是一种常见的操作。通过将连续的数值型数据转换为离散类别,能够更好地处理数据,尤其是在机器学习模型中进行分类问题的建模时。离散化能够简化数据结构,减少数据噪声,并提高模型的解释性。 本文将详细介绍如何使用 pandas 库中的 cut…...

解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作

目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中&#xff0c;同义词&#xff08;Synonym&#xff09;是对数…...

AI协助探索AI新构型的自动化创新概念

训练AI自生成输出模块化代码&#xff0c;生成元代码级别的AI功能单元代码&#xff0c;然后再由AI组织为另一个AI&#xff0c;实现AI开发AI的能力&#xff1b;用AI协助探索迭代新构型AI将会出现&#xff0c;并成为一种新的技术路线潮流。 有限结点&#xff0c;无限的连接形式&a…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(OLED设备层封装)

目录 OLED设备层驱动开发 如何抽象一个OLED 完成OLED的功能 初始化OLED 清空屏幕 刷新屏幕与光标设置1 刷新屏幕与光标设置2 刷新屏幕与光标设置3 绘制一个点 反色 区域化操作 区域置位 区域反色 区域更新 区域清空 测试我们的抽象 整理一下&#xff0c;我们应…...

【Redis】Redis 经典面试题解析:深入理解 Redis 的核心概念与应用

Redis 是一个高性能的键值存储系统&#xff0c;广泛应用于缓存、消息队列、排行榜等场景。在面试中&#xff0c;Redis 是一个高频话题&#xff0c;尤其是其核心概念、数据结构、持久化机制和高可用性方案。 1. Redis 是什么&#xff1f;它的主要特点是什么&#xff1f; 答案&a…...

TensorFlow 示例摄氏度到华氏度的转换(一)

TensorFlow 实现神经网络模型来进行摄氏度到华氏度的转换&#xff0c;可以将其作为一个回归问题来处理。我们可以通过神经网络来拟合这个简单的转换公式。 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 …...

7.DP算法

DP 在C中&#xff0c;动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09;是一种通过将复杂问题分解为重叠子问题来高效求解的算法设计范式。以下是DP算法的核心要点和实现方法&#xff1a; 一、动态规划的核心思想 重叠子问题&#xff1a;问题可分解为多个重…...

Baklib构建高效协同的基于云的内容中台解决方案

内容概要 随着云计算技术的飞速发展&#xff0c;内容管理的方式也在不断演变。企业面临着如何在数字化转型过程中高效管理和协同处理内容的新挑战。为应对这些挑战&#xff0c;引入基于云的内容中台解决方案显得尤为重要。 Baklib作为创新型解决方案提供商&#xff0c;致力于…...

在C语言多线程环境中使用互斥量

如果有十个银行账号通过不同的十条线程同时向同一个账号转账时&#xff0c;如果没有很好的机制保证十个账号依次存入&#xff0c;那么这些转账可能出问题。我们可以通过互斥量来解决。 C标准库提供了这个互斥量&#xff0c;只需要引入threads.头文件。 互斥量就像是一把锁&am…...

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…...

代码随想录刷题笔记

数组 二分查找 ● 704.二分查找 tips&#xff1a;两种方法&#xff0c;左闭右开和左闭右闭&#xff0c;要注意区间不变性&#xff0c;在判断mid的值时要看mid当前是否使用过 ● 35.搜索插入位置 ● 34.在排序数组中查找元素的第一个和最后一个位置 tips&#xff1a;寻找左右边…...

AI智慧社区--人脸识别

前端 人脸的采集按钮&#xff1a; 首先对于选中未认证的居民记录&#xff0c;进行人脸采集 前端的按钮 <el-form-item><el-button v-has"sys:person:info" type"info" icon"el-icon-camera" :disabled"ids.length < 0" …...

对象的实例化、内存布局与访问定位

一、创建对象的方式 二、创建对象的步骤: 一、判断对象对应的类是否加载、链接、初始化: 虚拟机遇到一条new指令&#xff0c;首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已经被加载、解析和初始化…...

React基础知识回顾详解

以下是React从前端面试基础到进阶的系统性学习内容&#xff0c;包含核心知识点和常见面试题解析&#xff1a; 一、React基础核心 JSX原理与本质 JSX编译过程&#xff08;Babel转换&#xff09;虚拟DOM工作原理面试题&#xff1a;React为何使用className而不是class&#xff1f;…...

开发第一个安卓页面

一&#xff1a;在java.com.example.myapplication下创建MainActivity的JAVA类 里面的代码要把xml的页面名字引入 二&#xff1a;如果没有这两个&#xff0c;可以手动创建layout文件夹和activity_main.xml activity_main.xml使用来做页面的。 三、找到这个文件 把你的JAVA类引入…...

物联网 STM32【源代码形式-ESP8266透传】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】

一、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;是一种基于发布/订阅模式的轻量级通讯协议&#xff0c;构建于TCP/IP协议之上。它最初由IBM在1999年发布&#xff0c;主要用于在硬件性能受限和网络状况不佳的情…...

微服务-配置管理

配置管理 到目前为止我们已经解决了微服务相关的几个问题&#xff1a; 微服务远程调用微服务注册、发现微服务请求路由、负载均衡微服务登录用户信息传递 不过&#xff0c;现在依然还有几个问题需要解决&#xff1a; 网关路由在配置文件中写死了&#xff0c;如果变更必须重…...

基于SpringBoot的智慧康老疗养院管理系统的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...