qt-C++笔记之事件过滤器

news2025/1/12 19:00:24

qt-C++笔记之事件过滤器

—— 杭州 2024-02-25


在这里插入图片描述

code review!

文章目录

  • qt-C++笔记之事件过滤器
    • 一.使用事件过滤器和不使用事件过滤器对比
      • 1.1.使用事件过滤器
      • 1.2.不使用事件过滤器
      • 1.3.比较
    • 二.Qt 中事件过滤器存在的意义
    • 三.为什么要重写QObject的eventFilter方法?使用QObject默认的eventFilter方法不可以吗?
    • 四.事件过滤器的使用场景
      • 4.1. 灵活的事件处理:
      • 4.2. 代码解耦:
      • 4.3. 条件事件处理:
      • 4.4. 监控和调试:
      • 4.5. 创建可重用的行为:
    • 五.使用事件过滤器和不使用事件过滤器优缺点
      • 使用事件过滤器
      • 不使用事件过滤器
    • 六.《Qt6 C++开发指南》——事件过滤器部分
    • 七.《Qt程序设计基础 基于银河麒麟桌面操作系统》

一.使用事件过滤器和不使用事件过滤器对比

在Qt框架中,事件过滤器通常通过重写QObject类的eventFilter()方法来实现。下面提供两个简单的示例,展示在Qt C++中使用和不使用事件过滤器的情况:

1.1.使用事件过滤器

首先,创建一个新的类(例如MyFilter),从QObject派生,并重写eventFilter()方法来拦截和处理特定的事件。

#include <QObject>
#include <QEvent>
#include <QDebug>

class MyFilter : public QObject {
    Q_OBJECT

protected:
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (event->type() == QEvent::KeyPress) {
            qDebug() << "A key press event has been filtered.";
            // 处理事件
            return true;  // 返回true表示事件已被处理,不需要进一步传递
        }
        // 其他事件传递给基类的eventFilter方法
        return QObject::eventFilter(obj, event);
    }
};

然后,你需要在你想要过滤其事件的对象上安装这个过滤器:

#include <QApplication>
#include <QWidget>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QWidget window;

    MyFilter *filter = new MyFilter(&window);
    window.installEventFilter(filter);  // 安装事件过滤器

    window.show();
    return a.exec();
}

1.2.不使用事件过滤器

如果不使用事件过滤器,你可能会直接在对象的事件处理方法中处理所有的事件,例如在QWidget的子类中重写keyPressEvent()方法:

#include <QWidget>
#include <QKeyEvent>
#include <QDebug>

class MyWidget : public QWidget {
    Q_OBJECT

protected:
    void keyPressEvent(QKeyEvent *event) override {
        qDebug() << "A key press event has been received.";
        // 处理事件
        QWidget::keyPressEvent(event);  // 调用基类的keyPressEvent方法
    }
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MyWidget window;

    window.show();
    return a.exec();
}

在这个例子中,MyWidget会接收并处理所有的按键事件,而不是通过一个单独的过滤器来进行筛选。

1.3.比较

使用事件过滤器的方式更加灵活,因为你可以在不修改原有类的情况下,通过安装或移除过滤器来动态改变事件处理行为。此外,过滤器可以用于多个对象,不需要为每个对象编写重复的事件处理代码。

而不使用事件过滤器的方式更加直接,通常用于处理特定对象的事件。这种方式能够保证事件不会被其他对象意外截获,但是如果需要在多个对象之间共享相同的事件处理逻辑,可能会导致代码重复。

二.Qt 中事件过滤器存在的意义

Qt框架中的事件过滤器(Event Filter)是一个强大的功能,它允许对象拦截和处理发给其他对象的事件。事件过滤器的存在意义主要体现在以下几个方面:

  1. 灵活的事件处理:在Qt中,通常情况下,事件是被发送到目标对象的事件处理函数中(如mousePressEventkeyPressEvent等)。通过安装事件过滤器,你可以在事件到达目标对象之前对其进行拦截和处理,这允许你在不修改目标对象代码的情况下增加额外的行为。

  2. 代码解耦:事件过滤器可以帮助你减少类之间的耦合。例如,可以在一个单独的类中处理所有相关的事件,而不是将这些处理逻辑分散到多个子类中。

  3. 条件事件处理:你可以根据需要决定是否要处理某个事件,或者在某些条件满足时改变事件的行为。事件过滤器可以基于动态条件(如应用程序的状态)来决定是否和如何处理事件。

  4. 监控和调试:事件过滤器可以用来监控事件流,帮助开发者理解事件是如何在应用程序中流转的,这对于调试事件相关的问题非常有用。

  5. 创建可重用的行为:通过事件过滤器,可以创建可以附加到多个对象上的通用行为,而无需每个对象都实现相同的事件处理代码。

要使用事件过滤器,你需要重写QObjecteventFilter方法,并使用installEventFilter方法将过滤器对象安装到目标对象上。当事件发生并且传递给目标对象之前,eventFilter方法会被调用,你可以在这个方法中决定如何处理事件。

下面是一个简单的例子,说明如何为一个对象安装事件过滤器:

class MyEventFilter : public QObject
{
protected:
    bool eventFilter(QObject *obj, QEvent *event) override
    {
        if (event->type() == QEvent::KeyPress) {
            // 处理按键事件
            // ...
            return true; // 返回true表示事件被处理,不再传递
        }
        // 将事件传递给基类的事件过滤器
        return QObject::eventFilter(obj, event);
    }
};

// 在某个地方使用事件过滤器
MyEventFilter *filter = new MyEventFilter();
targetObject->installEventFilter(filter);

在这个例子中,MyEventFilter类重写了eventFilter方法来处理按键事件。当目标对象targetObject接收到按键事件时,eventFilter方法会被调用,我们可以在这里决定如何处理该事件。如果我们返回true,则表示事件已经被处理并且不应该继续传递;如果返回false,事件将会继续传递给目标对象的相应事件处理方法。

三.为什么要重写QObject的eventFilter方法?使用QObject默认的eventFilter方法不可以吗?

在Qt中,QObject类提供了一个默认的实现eventFilter方法,但这个默认实现只是简单地返回false,表示它没有处理该事件,事件应该继续传递给目标对象的事件处理方法。换句话说,如果你不重写eventFilter方法,那么安装事件过滤器将没有任何实际效果,因为所有事件都会按照正常的流程继续传递。

重写eventFilter方法的目的是为了在事件到达目标对象之前介入处理流程。你可以在这个方法中编写自定义的逻辑来决定是否拦截某个事件,改变事件的默认行为,或者在事件传递到目标对象之前进行一些特殊处理。

下面是QObjecteventFilter方法默认实现的伪代码表示:

bool QObject::eventFilter(QObject *watched, QEvent *event)
{
    // 默认实现,不做任何处理,返回false表示不拦截事件
    return false;
}

当你创建一个新的类继承自QObject或者其子类,并且你希望该类能够以某种方式处理或者监控其他对象的事件时,你就需要提供eventFilter的自定义实现。例如,你可能想要记录所有的鼠标点击事件,或者在用户按下特定快捷键时触发某个动作。这时,你就需要重写eventFilter方法,如下所示:

class MyCustomFilter : public QObject
{
    // ...

protected:
    bool eventFilter(QObject *watched, QEvent *event) override
    {
        if (event->type() == QEvent::MouseButtonPress) {
            // 处理鼠标按下事件
            // ...
            return true; // 事件被处理,不再传递
        }
        // 对于不处理的事件,调用基类的eventFilter方法
        return QObject::eventFilter(watched, event);
    }
};

在这个例子中,MyCustomFilter类重写了eventFilter方法以便在鼠标按下时执行一些自定义操作。如果eventFilter方法返回true,则表示事件已经被处理,不应该继续传递;如果返回false,则事件会按照正常的事件处理流程继续传递给目标对象。

四.事件过滤器的使用场景

当然可以,下面是针对每个场景的main.cpp文件的完整示例。

4.1. 灵活的事件处理:

#include <QApplication>
#include <QLineEdit>
#include <QDebug>
#include <QObject>

class HelpEventFilter : 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_F1) {
                qDebug() << "Help requested for:" << obj;
                return true;
            }
        }
        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QLineEdit lineEdit;
    HelpEventFilter helpFilter;
    lineEdit.installEventFilter(&helpFilter);

    lineEdit.show();
    return app.exec();
}

4.2. 代码解耦:

#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <QObject>

class UpdateEventFilter : public QObject {
protected:
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (event->type() == QEvent::MouseButtonPress) {
            qDebug() << "Updating components due to click on:" << obj;
            return true;
        }
        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget widget;
    UpdateEventFilter updateFilter;
    widget.installEventFilter(&updateFilter);

    widget.show();
    return app.exec();
}

4.3. 条件事件处理:

#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <QObject>

class GameEventFilter : public QObject {
    bool gameRunning;

public:
    GameEventFilter(bool running) : gameRunning(running) {}

protected:
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (event->type() == QEvent::KeyPress && gameRunning) {
            qDebug() << "Game is running - event processed for:" << obj;
            return true;
        }
        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget widget;
    GameEventFilter gameFilter(true);
    widget.installEventFilter(&gameFilter);

    widget.show();
    return app.exec();
}

4.4. 监控和调试:

#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <QObject>

class DebugEventFilter : public QObject {
protected:
    bool eventFilter(QObject *obj, QEvent *event) override {
        qDebug() << "Event:" << event->type() << "for object:" << obj;
        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget widget;
    DebugEventFilter debugFilter;
    widget.installEventFilter(&debugFilter);

    widget.show();
    return app.exec();
}

4.5. 创建可重用的行为:

#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <QObject>
#include <QDragEnterEvent>
#include <QMimeData>

class DragDropEventFilter : public QObject {
protected:
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (event->type() == QEvent::DragEnter) {
            QDragEnterEvent *dragEvent = static_cast<QDragEnterEvent *>(event);
            if (dragEvent->mimeData()->hasFormat("text/plain")) {
                qDebug() << "Drag enter event for:" << obj;
                dragEvent->accept();
                return true;
            }
        }
        return QObject::eventFilter(obj, event);
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget widget;
    widget.setAcceptDrops(true);

    DragDropEventFilter dragDropFilter;
    widget.installEventFilter(&dragDropFilter);

    widget.show();
    return app.exec();
}

在每个例子中,我们创建了一个应用程序实例和一个主窗口部件,然后创建了一个事件过滤器并将其安装到主窗口部件上。在实际应用中,你可能需要调整过滤器逻辑以适应你的具体需求。这些示例中的eventFilter函数的返回值很重要,如果它返回true,则表明事件已被处理,不会再传递给对象;如果返回false,则事件会继续传递给对象的event方法。

五.使用事件过滤器和不使用事件过滤器优缺点

在计算机编程和系统设计中,事件过滤器是一种用来决定是否应该处理或忽略某个事件的机制。事件可以是用户操作、系统生成的消息或者是由硬件设备产生的信号等。使用事件过滤器和不使用事件过滤器可以带来不同的效果和影响,下面列举了一些对比点:

使用事件过滤器

优点:

  1. 效率提升:当事件数量很大时,过滤器可以帮助减少无关事件的处理,从而节省CPU时间和内存资源。
  2. 更好的用户体验:过滤器可以确保只有相关和重要的事件被处理,避免了不必要的干扰,提高应用程序的响应性。
  3. 可维护性:过滤器可以帮助组织和管理事件处理逻辑,使代码更加清晰,易于维护和更新。
  4. 灵活性:过滤器可以动态地添加或移除,方便地调整哪些事件应该被处理。
  5. 安全性:过滤掉不必要的或潜在危险的事件,可以减少安全风险。

缺点:

  1. 复杂性:设计和实现事件过滤器会增加系统的复杂度。
  2. 性能开销:虽然过滤器可以提高整体效率,但是过滤器本身的运行也会消耗一定的性能。
  3. 可能的错误过滤:如果过滤器逻辑设计不当,可能会错误地过滤掉应该处理的事件。

不使用事件过滤器

优点:

  1. 简单性:不需要考虑过滤逻辑,实现起来比较简单直接。
  2. 无额外性能开销:没有过滤器运行的开销,每个事件都直接送进事件处理流程。
  3. 完整性:所有事件都会被送至处理程序,没有遗漏的风险。

缺点:

  1. 效率低下:没有过滤机制意味着所有事件,无论是否相关,都会被处理,这可能会导致不必要的性能负担。
  2. 用户体验不佳:处理大量无关事件可能会导致应用程序响应变慢,影响用户体验。
  3. 可维护性差:随着事件处理逻辑的增多,代码可能变得难以管理和维护。
  4. 安全风险:处理所有事件可能会使系统面临更多的安全威胁,因为不加选择的处理可能包含恶意的事件。

总结来说,使用事件过滤器可以帮助提高系统效率,提升用户体验,加强安全性,并有助于代码维护。然而,它也会带来额外的复杂性和性能开销。不使用事件过滤器则在实现上更为简单,但可能会导致效率低下和维护困难等问题。在实际应用中,是否使用事件过滤器取决于具体的需求、资源限制和安全考虑。

六.《Qt6 C++开发指南》——事件过滤器部分

在这里插入图片描述

七.《Qt程序设计基础 基于银河麒麟桌面操作系统》

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

数据结构:链表的冒泡排序

法一&#xff1a;修改指针指向 //法二 void maopao_link(link_p H){if(HNULL){printf("头节点为空\n");return;}if(link_empty(H)){printf("链表为空\n");return;}link_p tailNULL;while(H->next->next!tail){link_p pH;link_p qH->next;while(q…

常见的音频与视频格式

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

【Unity】使用Video Player播放CG视频

1.在UI上新建一个Raw Image 2.添加Video Player 【参数详解】 Source&#xff1a;视频源类型&#xff0c;有Video Clip 和 URL两种Video Clip&#xff1a;视频片段&#xff0c;当Source选择video clip生效URL&#xff1a;视频路径&#xff0c;当Source选择URL生效Play On Awak…

洛谷C++简单题小练习day21—梦境数数小程序

day21--梦境数数--2.25 习题概述 题目背景 Bessie 处于半梦半醒的状态。过了一会儿&#xff0c;她意识到她在数数&#xff0c;不能入睡。 题目描述 Bessie 的大脑反应灵敏&#xff0c;仿佛真实地看到了她数过的一个又一个数。她开始注意每一个数码&#xff08;0…9&#x…

在IDEA中创建vue hello-world项目

工作中最近在接触vue前端项目&#xff0c;记录一下从0搭建一个vue hello world项目的步骤 1、本地电脑安装配置node、npm D:\Project\vue\hello-world>node -v v14.21.3 D:\Project\vue\hello-world>npm -v 6.14.18 D:\Project\vue\hello-world> 2、设置npm国内淘…

GPU over IP/IB:趋动OrionX产品的创新之路

在数字化转型的浪潮中&#xff0c;GPU over IP/IB技术正成为数据中心和云计算领域的一股新兴力量。这种技术通过将物理GPU资源虚拟化&#xff0c;实现了跨网络的高效利用&#xff0c;为AI、机器学习、科学计算等高性能计算任务提供了前所未有的灵活性和扩展性。 本文将深入探讨…

【管理咨询宝藏资料25】某能源集团五年发展战略报告

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏资料25】某能源集团五年发展战略报告 【关键词】战略规划、五年战略、管理咨询 【文件核心观点】 - LL应以快速做大做强为目标&#xff0c;专注…

VUE3环境搭建开发准备

VUE3 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;Vu…

常用实验室器皿耐硝酸盐酸进口PFA材质容量瓶螺纹盖密封效果好

PFA容量瓶规格参考&#xff1a;10ml、25ml、50ml、100ml、250ml、500ml、1000ml。 别名可溶性聚四氟乙烯容量瓶、特氟龙容量瓶。常用于ICP-MS、ICP-OES等痕量分析以及同位素分析等实验&#xff0c;也可在地质、电子化学品、半导体分析测试、疾控中心、制药厂、环境检测中心等机…

在autodl搭建stable-diffusion-webui+sadTalker

本文介绍在autodl.com搭建gpu服务器&#xff0c;实现stable-diffusion-webuisadTalker功能&#xff0c;图片音频 可生成视频。 autodl租GPU 自己本地部署SD环境会遇到各种问题&#xff0c;网络问题&#xff08;比如huggingface是无法访问&#xff09;&#xff0c;所以最好的方…

Java/Python/Go不同开发语言基础数据结构和相关操作总结-GC篇

Java/Python/Go不同开发语言基础数据结构和相关操作总结 1. 常见gc方式1.1 gc判断对象是否存活1.2 引用计数法1.2 标记-清除算法1.3 复制算法1.4 标记-压缩算法1.5 分代收集算法 2. java的gc方式以及垃圾回收器2.1 gc方式2.1 gc回收器2.1.1 Serial收集器2.1.2 ParNew收集器2.1.…

11:日志分析系统ELK|Elasticsearch|kibana

日志分析系统ELK&#xff5c;Elasticsearch&#xff5c;kibana 日志分析系统ELKELK概述Elasticsearch安装Elasticsearch部署Elasticsearch集群Elasticsearch插件 熟悉Elasticsearch的API调用_cat API创建 tedu 索引使用 PUT 方式增加数据查询数据修改数据删除数据 KibanaKibana…

VS连接MySQL以及找不到libmysql.dll的解决方法

VS连接数据库需要在项目中进行配置&#xff0c;具体可见 https://blog.csdn.net/weixin_40582034/article/details/115562097?ops_request_misc%257B%2522request%255Fid%2522%253A%2522170891897216800213058288%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522…

Java基于微信小程序的校园二手物品交易系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Sora:引领AI视频创作新时代(浅聊)

目录 一. 技术基础与发展二. 潜力与应用Sora的技术特点1. 高度智能的图像识别与生成能力2. 强大的语音识别与生成能力3. 创新的交互式视频编辑体验4. 高效的视频处理能力 Sora的应用场景1. 影视制作2. 教育培训3. 娱乐与游戏4. 商业广告 三. 面临的挑战四. 未来展望1. 结论2. 那…

【设计模式】5种创建型模式详解

创建型模式提供创建对象的机制,能够提升已有代码的灵活性和复用性。 常用的有:单例模式、工厂模式(工厂方法和抽象工厂)、建造者模式。不常用的有:原型模式。一、单例模式 1.1 单例模式介绍 1 ) 定义 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,此模…

选择 Python IDE(VSCode、Spyder、Visual Studio 2022和 PyCharm)

前言 当选择 Python 开发工具时&#xff0c;你需要考虑自己的需求、偏好和项目类型。下面是对VSCode、Spyder、Visual Studio 2022和 PyCharm的对比推荐总结&#xff1a; 结论 1、如果你专注于“数据科学”&#xff0c;选择SpyDer没错。 内容 Visual Studio Code (VS Code)…

视频和音频使用ffmpeg进行合并

1.下载ffmpeg 官网地址&#xff1a;https://ffmpeg.org/download.html 2.配置环境变量 此电脑右键点击 属性 - 高级系统配置 -高级 -环境变量 - 系统变量 path 新增 文件的bin路径 3.验证配置成功 ffmpeg -version 返回版本信息说明配置成功4.执行合并 ffmpeg -i 武家坡20…

淘宝镜像地址停止运行了 安装插件是失败如果解决

由于淘宝镜像目前已经停止更新运营了&#xff0c;所以导致在使用npm install安装无法成功 先查看一下安装镜像 npm config get registry //查看当前是不是淘宝镜像如果是新的淘宝镜像 重新安装新的淘宝镜像 npm config set registry https://registry.npmmirror.com/ 再次查看…

鸿蒙开发【WebGL】简单了解

WebGL的全称为Web Graphic Library(网页图形库)&#xff0c;主要用于交互式渲染2D图形和3D图形。目前HarmonyOS中使用的WebGL是基于OpenGL裁剪的OpenGL ES&#xff0c;可以在HTML5的canvas元素对象中使用&#xff0c;无需使用插件&#xff0c;支持跨平台。WebGL程序是由JavaScr…