当前位置: 首页 > 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;致力于…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...

spring Security对RBAC及其ABAC的支持使用

RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型&#xff0c;它将权限分配给角色&#xff0c;再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...