Qt/C++事件过滤器与控件响应重写的使用、场景的不同

在Qt/C++中,事件过滤器和控件响应重写是两种用于捕获和处理鼠标、键盘等事件的机制,它们的用途和使用场景不同,各有优劣。下面详细介绍它们的区别、各自适用的场景、以及混合使用的场景和注意事项。

1. 事件过滤器(Event Filter)

概述:

事件过滤器是Qt中的一种机制,允许一个对象监控并截获其它对象接收到的事件。通常用于在某些特定情况下,集中处理来自多个对象的事件。

实现方式:

通过QObject::installEventFilter()方法,可以将一个事件过滤器安装到一个或多个对象上。事件过滤器会截获该对象的所有事件,并通过QObject::eventFilter()方法对事件进行处理。你可以选择拦截事件或者让事件继续传递。

需求1:多个按钮点击时统一响应

需求描述: 假设在一个窗口中有多个按钮,每个按钮点击时执行相同的操作,此外,我们希望在点击按钮时触发同一事件,但又不希望单独为每个按钮重写事件处理函数。

解决方案:使用事件过滤器

通过事件过滤器,能够统一监控这些按钮的点击事件,而不需要逐个按钮去重写其mousePressEvent()

#include <QApplication>
#include <QPushButton>
#include <QWidget>
#include <QVBoxLayout>
#include <QEvent>
#include <QDebug>class ButtonEventFilter : public QObject {
protected:bool eventFilter(QObject *obj, QEvent *event) override {if (event->type() == QEvent::MouseButtonPress) {QPushButton *button = qobject_cast<QPushButton*>(obj);if (button) {qDebug() << "Button clicked:" << button->text();return true; // 阻止进一步的事件处理}}return QObject::eventFilter(obj, event); // 默认处理}
};int main(int argc, char *argv[]) {QApplication a(argc, argv);QWidget window;QVBoxLayout *layout = new QVBoxLayout(&window);QPushButton *button1 = new QPushButton("Button 1");QPushButton *button2 = new QPushButton("Button 2");QPushButton *button3 = new QPushButton("Button 3");layout->addWidget(button1);layout->addWidget(button2);layout->addWidget(button3);ButtonEventFilter *filter = new ButtonEventFilter();button1->installEventFilter(filter);button2->installEventFilter(filter);button3->installEventFilter(filter);window.show();return a.exec();
}
分析:
  • 这里我们定义了一个ButtonEventFilter类,继承自QObject并重写了eventFilter()方法。
  • installEventFilter()方法将事件过滤器应用于每个按钮,统一捕获它们的点击事件,而不必为每个按钮单独编写事件处理逻辑。
  • 这种方法适合需要集中处理多个控件的类似事件的场景。

适用场景:
  • 多个对象的统一事件处理: 当需要在一个地方集中处理多个对象的事件时,可以使用事件过滤器。例如,统一处理多个按钮的键盘输入或鼠标点击事件。
  • 跨组件的事件处理: 事件过滤器可以用于在多个组件之间的事件监控和处理。比如,监控某些窗口之外的点击事件。
  • 拦截全局事件: 如果你需要监控整个应用程序的某些类型的事件(如按键或鼠标事件),可以将事件过滤器安装在应用程序对象上。

注意事项:
  • 性能开销: 由于事件过滤器会拦截和检查大量事件,如果在应用程序中广泛使用,可能会引入性能问题。特别是在大型应用中,尽量避免在所有控件上安装过滤器,而是集中在特定的几个控件上。
  • 事件传递: 如果需要让事件继续传递到目标对象,必须在事件过滤器中返回false。否则,事件将会被拦截,不会传递给目标控件。

2. 控件事件响应重写(Event Handler Override)

概述:

每个Qt控件都有自己的事件处理函数,比如mousePressEvent()keyPressEvent()等。你可以通过重写这些事件处理函数来定制控件对特定事件的响应。

实现方式:

通过继承控件类并重写特定的事件处理函数(如mousePressEvent()keyPressEvent()),可以定制对特定事件的处理逻辑。

需求2:某个控件有特殊的键盘事件响应

需求描述: 假设我们有一个输入框(QLineEdit),我们希望当用户按下Enter键时,执行特定操作,而其它控件对Enter键没有特殊反应。

解决方案:使用事件重写

在这种情况下,可以直接继承QLineEdit并重写keyPressEvent()函数。

#include <QApplication>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QDebug>class MyLineEdit : public QLineEdit {
protected:void keyPressEvent(QKeyEvent *event) override {if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {qDebug() << "Enter key pressed!";} else {QLineEdit::keyPressEvent(event);  // 传递给父类默认处理}}
};int main(int argc, char *argv[]) {QApplication a(argc, argv);QWidget window;QVBoxLayout *layout = new QVBoxLayout(&window);MyLineEdit *lineEdit = new MyLineEdit();layout->addWidget(lineEdit);window.show();return a.exec();
}
分析:
  • MyLineEdit类继承自QLineEdit,并重写了keyPressEvent()函数,用来捕获并处理Enter键的按下事件。
  • 当按下Enter键时,控制台会打印相应的消息。其它键则依然会按默认方式处理。
  • 这种方法适用于特定控件需要自定义键盘或鼠标事件的场景。

适用场景:
  • 特定控件的事件处理: 当你希望某个特定控件对事件有特定的行为时,可以通过重写该控件的事件处理函数。例如,一个自定义按钮在鼠标点击时执行特定操作。
  • 控件特定的细粒度控制: 如果只想处理某个控件的特定事件(如单击、双击等),而不影响其他控件,可以选择重写事件响应函数。
  • 自定义控件: 如果你在创建自定义控件并希望它具有特定的事件行为,重写事件处理函数是常见的方法。
注意事项:
  • 维护性: 如果控件继承层次复杂,重写多个事件处理函数可能增加代码的复杂性和维护成本。
  • 传递事件: 如果需要在重写的事件处理函数中保持父类的默认行为,需要在重写函数中调用父类的事件处理函数。例如,在重写mousePressEvent()时调用QWidget::mousePressEvent(event)

3. 混合使用场景

在某些场景下,你可能会混合使用事件过滤器和事件响应重写,以充分利用它们的优势。以下是一些混合使用的典型场景:

需求3:全局监控键盘事件并同时处理特定控件的自定义行为

需求描述: 假设你希望全局监控键盘按下事件,使用快捷键关闭窗口;同时,还希望窗口内的某些按钮在点击时执行自定义操作。

解决方案:混合使用事件过滤器和事件重写
  1. 使用事件过滤器来监控全局的键盘事件。
  2. 对按钮点击事件使用控件事件重写实现个性化处理。
#include <QApplication>
#include <QPushButton>
#include <QWidget>
#include <QVBoxLayout>
#include <QKeyEvent>
#include <QDebug>class GlobalEventFilter : public QObject {
protected:bool eventFilter(QObject *obj, QEvent *event) override {if (event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);if (keyEvent->key() == Qt::Key_Escape) {qDebug() << "Escape key pressed!";return true; // 拦截 Escape 键}}return QObject::eventFilter(obj, event); // 默认处理}
};class MyButton : public QPushButton {
public:MyButton(const QString &text) : QPushButton(text) {}protected:void mousePressEvent(QMouseEvent *event) override {qDebug() << "Custom behavior for" << text();QPushButton::mousePressEvent(event); // 保留父类行为}
};int main(int argc, char *argv[]) {QApplication a(argc, argv);QWidget window;QVBoxLayout *layout = new QVBoxLayout(&window);MyButton *button1 = new MyButton("Button 1");MyButton *button2 = new MyButton("Button 2");layout->addWidget(button1);layout->addWidget(button2);// 全局事件过滤器,用于捕获键盘事件GlobalEventFilter *filter = new GlobalEventFilter();a.installEventFilter(filter);window.show();return a.exec();
}
分析:
  • 在这里,我们通过GlobalEventFilter来监控整个应用程序的键盘事件(例如,捕获Escape键关闭窗口的功能)。
  • 同时,我们通过继承QPushButton并重写其mousePressEvent(),实现了自定义按钮的点击行为。
  • 这种混合方式适用于既需要全局事件处理又需要特定控件自定义行为的场景。
  • 局部控件的自定义行为 + 全局事件过滤: 如果你希望某些控件有特殊的事件处理行为,可以通过重写这些控件的事件处理函数,同时你可以通过事件过滤器捕获整个窗口或应用程序的其他全局事件。例如,某个按钮有特殊的按键响应,而同时你希望捕获所有控件的键盘按下事件用于全局快捷键处理。

  • 多控件共享事件处理 + 个别控件的精细化控制: 如果你有一组控件需要共享某些事件处理逻辑(如鼠标点击),可以使用事件过滤器来处理,同时对其中一些控件,通过重写事件处理函数,来进行精细化控制。例如,一个界面上多个按钮共享鼠标事件过滤逻辑,但是有几个按钮有特定的右键菜单响应。


使用建议和注意事项

  1. 事件过滤器的使用建议:

    • 事件过滤器更适合跨多个对象或全局的事件处理需求,而不是处理单个控件的事件。特别是需要在一个地方集中处理事件时非常方便。
    • 在复杂的UI层次结构中,尽量避免将事件过滤器安装在每个控件上,因为这可能会影响性能。可以选择在重要的父控件或窗口上安装事件过滤器。
  2. 控件事件重写的使用建议:

    • 重写事件处理函数时,尽量保持代码的简洁和可维护性。如果有多个类似控件需要重写,可以考虑将通用逻辑抽象到父类中。
    • 如果需要保留默认的事件处理行为,请不要忘记在重写的事件函数中调用父类的事件处理函数。
  3. 混合使用的建议:

    • 使用事件过滤器来处理全局或多个控件的事件逻辑,同时在特定控件上重写事件响应函数,以实现更加精细的控制。
    • 注意避免在事件过滤器和重写的事件处理函数中重复处理相同的事件,以免造成混乱或性能问题。

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

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

相关文章

全能OCR神器GOT-OCR2.0整合包部署教程

项目地址:https://github.com/Ucas-HaoranWei/GOT-OCR2.0 整合包下载&#xff1a;https://pan.quark.cn/s/3757da820e65 显卡建议使用RTX 30以上的 ①先安装NVIDIA显卡驱动&#xff1a; https://www.nvidia.cn/drivers/lookup/ 输入显卡型号搜索就行 ②安装CUDA 工具包 cu…

Django 聚合查询

文章目录 一、聚合查询二、使用步骤1.准备工作2.具体使用3.分组查询&#xff08;annotate&#xff09;1.定义2.使用3.具体案例 4.F() 查询1.定义2.使用 5.Q() 查询1.定义2.查询 一、聚合查询 使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum&#xff0…

力扣 2529.正整数和负整数的最大计数

文章目录 题目介绍解法 题目介绍 解法 采用红蓝染色体法&#xff0c;具体介绍参考 红蓝染色体法 通过红蓝染色体法可以找到第一个大于大于target的位置&#xff0c;使所以本题可以找第一个大于0的位置&#xff0c;即负整数的个数&#xff1b;数组长度 - 第一个大于1的位置即正…

【踩坑】装了显卡,如何让显示器从主板和显卡HDMI都输出

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 背景介绍 装了显卡后&#xff0c;开机默认是从显卡的HDMI输出&#xff0c;但这很不方便。如何让视频仍然从主板输出&#xff1f;或者说让显卡HDMI和主板…

切线空间:unity中shader切线空间,切线矩阵,TBN矩阵 ,法线贴图深度剖析

unity中shader切线空间 看了网上各种解释&#xff0c;各种推理。直接脑袋大。感觉复杂的高大上。当深入了解后&#xff0c;才发是各种扯淡。 一切从模型法向量开始 在shader中&#xff0c;大部分的光照计算都是与法向量有关。通过法向量和其他向量能计算出模型在光线照射下的…

MyBatis-Plus分页查询、分组查询

目录 准备工作1. 实体类2. Mapper类3. 分页插件4. 数据 分页查询1. 使用条件构造器2. 使用自定义sql 分组查询1. 分组结果类2. 自定义sql3. 测试类 准备工作 1. 实体类 对地址字段address使用字段类型转换器&#xff0c;将List转为字符串数组保存在数据库中 package com.exa…

【CSS Tricks】一种基于AV1视频格式的现代图像格式-AVIF

引言 AV1图像文件格式&#xff08;英语&#xff1a;AV1 Image File Format&#xff0c;简称AVIF&#xff09;是由开放媒体联盟&#xff08;AOM&#xff09;开发&#xff0c;采用AV1视讯编码技术压缩图像的一种图像文件格式&#xff0c;能用来储存一般的图像和动态图像。AVIF和苹…

torch.embedding 报错 IndexError: index out of range in self

文章目录 1. 报错2. 原因3. 解决方法 1. 报错 torch.embedding 报错&#xff1a; IndexError: index out of range in self2. 原因 首先看下正常情况&#xff1a; import torch import torch.nn.functional as Finputs torch.tensor([[1, 2, 4, 5], [4, 3, 2, 9]]) embedd…

【Git原理与使用】版本管理与分支管理(1)

目录 一、基本操作 1、初识Git 2、Git安装[Linux-centos] 3、Git安装[ Linnx-ubuntu] 4、创建git本地仓库 5、配置Git 6、认识工作区、暂存区、版本库 7、添加文件 8、查看历史提交记录 9、查看.git文件目录结构 10、查看版本库对象的内容 11、小结&#xff08;在本地的.git仓库…

JVM常用参数配置

JVM常用参数配置 简单的java命令后面跟上配置参数。 -XX&#xff0c;JVM启动参数的一种类型&#xff0c;属于高级。 &#xff0c;开启的意思 &#xff1a;&#xff0c;设置具体参数 #jvm启动参数不换行 #设置堆内存 -Xmx4g -Xms4g #指定GC算法 -XX:UseG1GC -XX:MaxGCPauseM…

Qt_多元素控件

目录 1、认识多元素控件 2、QListWidget 2.1 使用QListWidget 3、QTableWidget 3.1 使用QListWidget 4、QTreeWidget 4.1 使用QTreeWidget 5、QGroupBox 5.1 使用QGroupBox 6、QTabWidget 6.1 使用QTabWidget 结语 前言&#xff1a; 在Qt中&#xff0c;控件之间…

《深度学习》—— 神经网络模型对手写数字的识别

神经网络模型对手写数字的识别 import torch from torch import nn # 导入神经网络模块 from torch.utils.data import DataLoader # 数据包管理工具&#xff0c;打包数据, from torchvision import datasets # 封装了很多与图像相关的模型&#xff0c;数据集 from torchvi…

分布式事务seata

文章目录 CAP理论BASE 理论seata解决分布式事务seata重要对象XA模式AT模式TCC模式saga模式 CAP理论 CAP理论指出在分布式系统中三个属性不可能同时满足。 Consistency 一致性&#xff1a;在分布式的多个节点&#xff08;副本&#xff09;的数据必须是一样的&#xff08;强一致…

展锐平台的手机camera 系统开发过程

展锐公司有自己的isp 图像处理引擎&#xff0c;从2012 年底就开始在智能手机上部署应用。最初的时候就几个人做一款isp的从hal 到kernel 驱动的完整软件系统&#xff0c;分工不是很明确&#xff0c;基本是谁擅长哪些就搞哪些&#xff0c;除了架构和编码实现之外&#xff0c;另外…

软硬件项目运维方案(Doc原件完整版套用)

1 系统的服务内容 1.1 服务目标 1.2 信息资产统计服务 1.3 网络、安全系统运维服务 1.4 主机、存储系统运维服务 1.5 数据库系统运维服务 1.6 中间件运维服务 2 运维服务流程 3 服务管理制度规范 3.1 服务时间 3.2 行为规范 3.3 现场服务支持规范 3.4 问题记录规范…

【数据结构】排序算法---基数排序

文章目录 1. 定义2. 算法步骤2.1 MSD基数排序2.2 LSD基数排序 3. LSD 基数排序动图演示4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 结语 ⚠本节要介绍的不是计数排序 1. 定义 基数排序&#xff08;英语&#xff1a;Radix sort&#xff09;是一种非比较型的排序算法&…

秋招常问的面试题:Cookie和Session的区别

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

LeetCode[中等] 3. 无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 思路&#xff1a;滑动窗口&#xff0c;设置左右指针left与right&#xff0c;maxLength存储长度 利用HashSet性质&#xff0c;存储滑动窗口中的字符 如果没有重复的&#xff0c;那么right继续向…

LeetCode_sql_day28(1767.寻找没有被执行的任务对)

描述&#xff1a;1767.寻找没有被执行的任务对 表&#xff1a;Tasks ------------------------- | Column Name | Type | ------------------------- | task_id | int | | subtasks_count | int | ------------------------- task_id 具有唯一值的列。 ta…

无人机企业合法运营必备运营合格证详解

无人机企业运营合格证&#xff0c;是由国家相关航空管理部门&#xff08;如中国民用航空局或其授权机构&#xff09;颁发的&#xff0c;用于确认无人机企业具备合法、安全、高效运营无人机能力的资质证书。该证书是无人机企业开展商业运营活动的必要条件&#xff0c;标志着企业…