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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂 Faiss:开启高维向量高效检索的大门

一、引言 在大数据与人工智能蓬勃发展的当下&#xff0c;高维向量数据如潮水般涌现。无论是图像、音频、文本&#xff0c;还是生物信息领域&#xff0c;都离不开高维向量来精准刻画数据特征。然而&#xff0c;在海量的高维向量数据中进行快速、准确的相似性搜索&#xff0c;却…

Openfga 授权模型搭建

1.根据项目去启动 配置一个 openfga 服务器 先创建一个 config.yaml文件 cd /opt/openFGA/conf touch ./config.yaml 怎么配置&#xff1f; 根据官网来看 openfga/.config-schema.json at main openfga/openfga GitHub 这里讲述详细的每一个配置每一个类型 这些配置有…

三次方根pow

给定一个浮点数n&#xff0c;求它的三次方根。 输入格式: 共一行&#xff0c;包含一个浮点数n,−10000≤n≤10000。 输出格式: 共一行&#xff0c;包含一个浮点数&#xff0c;表示问题的解。 注意&#xff0c;结果保留6位小数。 输入样例: 1000.00输出样例: 10.000000 …

你好!这是我自己的CSDN博客!

写于2025年1月30日 我是一个普通的嵌入式软件程序员&#xff0c;喜欢研究Linux&#xff08;应用层跟内核从都有粗浅的涉略&#xff09;&#xff0c;单片机&#xff0c;操作系统和计算机体系架构等内容&#xff0c;目前是一枚普通的本科生。 笔者是一个朴素的开源主义者&#xf…

11 Spark面试真题

11 Spark大厂面试真题 1. 通常来说&#xff0c;Spark与MapReduce相比&#xff0c;Spark运行效率更高。请说明效率更高来源于Spark内置的哪些机制&#xff1f;2. hadoop和spark使用场景&#xff1f;3. spark如何保证宕机迅速恢复?4. hadoop和spark的相同点和不同点&#xff1f;…

赛博算卦之周易六十四卦JAVA实现:六幺算尽天下事,梅花化解天下苦。

佬们过年好呀~新年第一篇博客让我们来场赛博算命吧&#xff01; 更多文章&#xff1a;个人主页 系列文章&#xff1a;JAVA专栏 欢迎各位大佬来访哦~互三必回&#xff01;&#xff01;&#xff01; 文章目录 #一、文化背景概述1.文化起源2.起卦步骤 #二、卦象解读#三、just do i…

列表(列表是什么)

你将学习列表是什么以及如何使用列表元素。列表让你能够在一个地方存储成组的信息&#xff0c;其中可以只包含几个元素&#xff0c;也可以包含数百万个元素。 列表是新手可直接使用的最强大的Python功能之一&#xff0c;它融合了众多重要的编程概念。 列表是什么 列表 由一系列…

Myeclipse最新版本 C1 2019.4.0

Myeclipse C1 2019.4.0下载地址&#xff1a;链接: https://pan.baidu.com/s/1MbOMLewvAdemoQ4FNfL9pQ 提取码: tmf6 1.1、什么是集成开发环境? ★集成开发环境讲究-站式开发&#xff0c;使用这个工具即可。有提示功能&#xff0c;有自动纠错功能。 ★集成开发环境可以让软件开…

CNN的各种知识点(一):卷积神经网络CNN通道数的理解!

卷积神经网络CNN通道数的理解&#xff01; 通道数的核心概念解析1. 通道数的本质 2. 单张灰度图的处理示例&#xff1a; 3. 批量输入的处理通道与批次的关系&#xff1a; 4. RGB三通道输入的处理计算过程&#xff1a;示例&#xff1a; 5. 通道数的实际意义6. 可视化理解(1) 单通…

力扣116. 填充每个节点的下一个右侧节点指针

Problem: 116. 填充每个节点的下一个右侧节点指针 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 本题目的难点在于对于不同父节点的邻接问题因此我们可以抽象将两两节点为一组&#xff08;不同父节点的两个孩子节点也抽象为一组&#xff09…

Deepseek r1模型对医疗大模型的发展有什么影响?

1. 强化学习技术的突破与创新 DeepSeek R1 是一款基于纯强化学习&#xff08;RL&#xff09;训练的开源推理模型&#xff0c;其核心在于通过环境反馈而非人工标注数据来优化模型行为。这种方法不仅降低了对标注数据的依赖&#xff0c;还显著提升了模型的推理能力。例如&#x…

python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。 按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位异或运算&#xff1a; 两个等长度二进制数上下对齐&#xff0c;相…

面试经典150题——图的广度优先搜索

文章目录 1、蛇梯棋1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、最小基因变化2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、单词接龙3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 1、蛇梯棋 1.1 题目链接 点击跳转到题目位置 1.2 题目描述 给你一…

【架构面试】一、架构设计认知

涉及分布式锁、中间件、数据库、分布式缓存、系统高可用等多个技术领域&#xff0c;旨在考查候选人的技术深度、架构设计能力与解决实际问题的能力。 1. 以 Redis 是否可以作为分布式锁为例&#xff1a; 用 Redis 实现分布式锁会存在哪些问题&#xff1f; 死锁&#xff1a;如果…

MySQL基本架构SQL语句在数据库框架中的执行流程数据库的三范式

MySQL基本架构图&#xff1a; MySQL主要分为Server层和存储引擎层 Server层&#xff1a; 连接器&#xff1a;连接客户端&#xff0c;获取权限&#xff0c;管理连接 查询缓存&#xff08;可选&#xff09;&#xff1a;在执行查询语句之前会先到查询缓存中查看是否执行过这条语…

跟李沐学AI:视频生成类论文精读(Movie Gen、HunyuanVideo)

Movie Gen&#xff1a;A Cast of Media Foundation Models 简介 Movie Gen是Meta公司提出的一系列内容生成模型&#xff0c;包含了 3.2.1 预训练数据 Movie Gen采用大约 100M 的视频-文本对和 1B 的图片-文本对进行预训练。 图片-文本对的预训练流程与Meta提出的 Emu: Enh…

C++模板初识

文章目录 一、函数模板1. 函数模板2. 函数模板、模板的特例化、非模板函数的重载关系3. 外部调用4. 模板的非类型参数5. 代码示例 二、类模板 一、函数模板 1. 函数模板 模板函数&#xff1a;在函数调用点&#xff0c;编译器用用户指定的类型&#xff0c;从原模板实例化一份函…

深入MapReduce——从MRv1到Yarn

引入 我们前面篇章有提到&#xff0c;和MapReduce的论文不太一样。在Hadoop1.0实现里&#xff0c;每一个MapReduce的任务并没有一个独立的master进程&#xff0c;而是直接让调度系统承担了所有的worker 的master 的角色&#xff0c;这就是Hadoop1.0里的 JobTracker。在Hadoop1…

Baklib深入解析企业内容管理与内容中台的本质差异

内容概要 在当前信息化快速发展的时代&#xff0c;企业迫切需要高效的内容管理解决方案。企业内容管理&#xff08;ECM&#xff09;和内容中台是满足这一需求的两种不同系统。企业内容管理的主要作用是对企业内部的各种文档、数据进行整理和存储&#xff0c;确保信息资源的整合…

Ansible介绍与入门学习

一、Ansible的介绍&#xff08;Ansible is a radically simple IT automation engine 极简的IT自动化工具&#xff09; 1.Ansible是一款 运维的自动化工具&#xff0c;常用于软件部署自动化、配置自动化、管理自动化等&#xff0c;其内置大量的功能模块来满足日常的工作需要…