【C++】 Qt-事件(下)(事件过滤、自定义事件)

2023-11-14

事件过滤

event()函数是一个protected的函数,这意味着我们要想重写event(),必须继承一个已有的组件类,——重写其event()函数。event()函数的确有一定的控制,不过有时候我的需求更严格一些:我希望那些组件根本看不到这种事件。event()函数虽然可以拦截,但其实也是接收到了事件。我连让它收都收不到。这样做的好处是,模拟一种系统根本没有那个事件的效果,所以其它组件根本不会收到这个事件,也无需修改自己的事件处理函数。所以我们可以使用事件过滤器,事件过滤器给我们一种能力,让我们能够完全移除某种事件。事件过滤器可以安装到任意QObject类型上面,并且可以安装多个。

我们需要用到2个函数:

QObject::installEventFilter:安装过滤器

void installEventFilter(QObject *filterObj)

filterObj:监控者,包含eventFilter事件过滤器的对象,当this发生事件时,会先执行filterObj对象中的过滤器,再分发事件。

QObject::eventFilter:过滤器函数

virtual bool eventFilter(QObject *watched, QEvent *event);

watch被过滤器监视的对象,event:发生的事件,当watched对象发生事件时,会先调用过滤,在进行event()分发。

返回true代表,拦截成功,事件将不会再继续传递。

返回false代表,放行。

函数执行顺序:eventFilter(事件过滤) -> event(事件分发) -> event Handler(具体事件处理器)。

例子:在窗口界面上添加line edit 和 plain text edit 组件并用label约定为密码和描述。

针对于密码输入组件,我们规定只能输入字母,对描述的内容,我们约定滑轮中键按下且滚动时,为放大或缩小文本。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eunTemw5-1688529688054)(C++.assets/image-20230630230844290.png)]

对于上述要求,我们使用事件的重写,分发完全可以做到,但是需要我们自定义类、继承组件并提升。如果界面的组件有很多,每一个都需要自定义组件将导致增加很多类,带来代码管理上的麻烦。

首先我们在主窗口cpp中安装对应的过滤器

    //安装过滤器,参数:由谁监控(事件集中处理者)
    ui->lineEdit_pass->installEventFilter(this);
    ui->plainTextEdit->installEventFilter(this);

然后在QObject类中找到过滤器函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3jxWen2O-1688529688055)(C++.assets/image-20230630231307501.png)]

拿到主窗口类中进行重写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7xDBzWEc-1688529688055)(C++.assets/image-20230630231338206.png)]

定义:

//watched:发生了某个事件的对象,event: 发生了什么事件
bool MainWindow::eventFilter(QObject *watched, QEvent *event){

    if(watched == ui->lineEdit_pass){  //如果密码输入框发生了事件
        if(event->type() == QEvent::KeyPress){
            QKeyEvent *pKey = (QKeyEvent*) event;  //强转为具体的键盘事件

            if(Qt::Key_A <= pKey -> key() && pKey -> key() <= Qt::Key_Z){  //如果是字母,不拦截
                qDebug()<<"放行:" <<pKey->key();


            }else{  //拦截
                qDebug()<<"拦截:" <<pKey->key();
                return true;  //
            }
        }


    }else if(watched == ui->plainTextEdit){

    }

    return QMainWindow::eventFilter(watched,event);  //调用父类的拦截函数(放行)
}

然后我们可以在设计窗口中将文本输入框中的输入方式改为密码输入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3FPDiVLM-1688529688055)(C++.assets/image-20230630231622991.png)]

这样我们在输入时密码就不会显示出来了

运行效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aA36hLjG-1688529688056)(C++.assets/image-20230630231725968.png)]

当我们输入英文字母时就会放行,输入其他时就会拦截

下面再来实现按下鼠标中间并滚动去放大缩小说明中的字体

else if(watched == ui->plainTextEdit){
        if(event->type() == QEvent::Wheel){  //如果是滑轮事件
            QWheelEvent * pWheel = (QWheelEvent *)event;

            if(pWheel->buttons() == Qt::MiddleButton){  //如果鼠标中建按下
                qDebug() << "x= " << pWheel->angleDelta().x();   //Alt+滑轮上滚动 +120 下 -120
                qDebug() << "y= " << pWheel->angleDelta().y();   //滑轮上滚动 +120 下 -120
                //1:8 -> 滚动15读 
                if(pWheel->angleDelta().y() > 0){
                    ui->plainTextEdit->zoomIn();  //放大
                }else{
                    ui->plainTextEdit->zoomOut();  //缩小
                }
            }
        }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A88JlAAB-1688529688056)(C++.assets/image-20230701133919077.png)]

自定义事件

我们在界面上添加两个spin box用作计算的两个数,combo box作为计算的规则,push button将计算的结果以事件的形似发送出去。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8DlQ5x27-1688529688056)(C++.assets/image-20230701135818216.png)]

首先我们在主窗口的构造中添加好四种规则

    ui->comboBox->addItems(QStringList{"+","-","*","/"});

然后将计算按钮转到槽,然后在槽函数中获取数值

void MainWindow::on_pushButton_2_clicked()
{
    //获取数值
    int v1 = ui->spinBox1->value();
    int v2 = ui->spinBox2->value();
    
    QString str = ui->comboBox->currentText();  
    
}

在之后我们去自定义一个类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pNZtPIg3-1688529688057)(C++.assets/image-20230701140349307.png)]

将继承父类修改为QEvent,构造函数参数改为事件的类型,添加事件携带的信息

类头文件:

#ifndef MYEVENT_H
#define MYEVENT_H

#include <QEvent>
#include <QString>

class MyEvent : public QEvent
{
    //Q_OBJECT
public:
    explicit MyEvent(Type type);

    int m_v1;
    int m_v2;
    QString m_rule;
};

#endif // MYEVENT_H

类源文件:

#include "myevent.h"

MyEvent::MyEvent(Type type) : QEvent(type),m_v1(0),m_v2(0)
{

}

在槽函数中定义事件对象并填充数据,在槽函数外要定义个全局的自定义事件类型

//自定义事件类型:User ~ MaxUser
QEvent::Type myEventType = QEvent::User;
    MyEvent eve(myEventType);  //定义事件对象
    //填充数据
    eve.m_rule = str;
    eve.m_v1 = v1;
    eve.m_v2 = v2;

然后我们要发送自定义事件,但是没有接收窗口

所以我们创建一个dialog窗口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wSaeAu8e-1688529688057)(C++.assets/image-20230701161558492.png)]

在这个窗口中加入label组件

之后我们去main文件中创建dialog窗口的对象,但是我们在这个窗口创建的对象并不能在槽函数中使用,所以我们在全区位置创建一个该类型的指针指向这个对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0bm8jVI-1688529688057)(C++.assets/image-20230701161806061.png)]

这样我们在槽函数就可以使用这个窗口作为接收窗口了,不要忘了包含dialog的头文件

    extern Dialog* pdia;  //声明
    QCoreApplication::sendEvent(pdia,&eve);  //发送自定义事件

我们在QObject类中找到用户事件函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h9BS697v-1688529688057)(C++.assets/image-20230701162139768.png)]

将它拿到dialog类中进行重写定义

在这个函数中实现对数据的加减乘除并显示

void Dialog::customEvent(QEvent *event){
    extern QEvent::Type myEventType;
    if(event->type() == myEventType){  //如果是自定义事件

        MyEvent* myEve = (MyEvent*)event;  //强转为自定义的事件

        int ret = 0;
        if(myEve->m_rule == "+"){
            ret = myEve->m_v1 + myEve->m_v2;
        }else if(myEve->m_rule == "-"){
            ret = myEve->m_v1 - myEve->m_v2;
        }else if(myEve->m_rule == "*"){
            ret = myEve->m_v1 * myEve->m_v2;
        }else if(myEve->m_rule == "/"){
            ret = myEve->m_v1 / myEve->m_v2;
        }

        ui->label->setText(QString("%1 %2 %3 = %4").arg(myEve->m_v1).arg(myEve->m_rule).arg(myEve->m_v2).arg(ret));

        this->show();  //显示窗口
    }
}

这样就可以了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4YAHwZJ-1688529688058)(C++.assets/image-20230701162441888.png)]

刚才我们用的是sendEvent函数发送事件

现在我们换一种方式发送,postEvent

经过测试我们发现send会阻塞而post为非阻塞

    MyEvent *pEve = new MyEvent(myEventType);
    pEve->m_rule = str;
    pEve->m_v1 = v1;
    pEve->m_v2 = v2;
    QCoreApplication::postEvent(pdia,pEve);  //发送短信,非阻塞

现在我们想让结果显示3秒之后窗口自动去关闭

所以我们还要去用一下定时器事件,因为是要关闭dialog窗口,所以在dialog源文件中创建定时器,参数为3000毫秒,他会返回一个定时器id,所以我们要在类成员属性中创建一个

    int m_timerId;
    //设定定时器
    m_timerId = this->startTimer(3000);

接下来就是对定时器事件进行实现了,还记得我们找用户事件处理函数时上边有一个定时器处理函数,都是在QObject类中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHb2iH1i-1688529688058)(C++.assets/image-20230701165037865.png)]

我们还是将这个函数拿到dialog类中进行重写

void Dialog::timerEvent(QTimerEvent *event){
    if(event->timerId() == m_timerId){  //我设定的定时器除法了
        this->hide();
        this->killTimer(m_timerId);  //停止定时器
    }
}

这样就可以了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】 Qt-事件(下)(事件过滤、自定义事件) 的相关文章

  • 如何将变量的全部内容发送/导出到文本文件/xml 文件/剪贴板?

    我想将实例的内容 最好以树形形式 发送给某人 打印屏幕是不行的 因为类太复杂了 您需要将输出转回实例吗 在这种情况下 其他答案都是正确的 如果您只想手动检查实例的内容 理想情况下您的类都将实现toString 你可以将其重定向到一个文件 如
  • 如何使用 Maven Failsafe 插件运行 JUnit 5 集成测试?

    当我运行命令时 Maven Failsafe 插件找不到我的 JUnit 5 集成测试mvn clean failsafe integration test 尽管它可以找到文件 我有junit jupiter api and junit j
  • 如何在log4j的配置文件中为文件附加器提供环境变量路径

    我有一个log4j xml配置文件 和一个RollingFileAppender我需要提供用于存储日志的文件路径 问题是我的代码将作为可运行的 jar 部署在 Unix 机器上 所以如果我传递这样的参数 value logs message
  • GET 请求的 Spring 注解

    这两种spring GET方法有什么区别呢 哪一种是首选方法 Component Scope request Path public class TestComponent GET Path hello public String prin
  • 在命令行java中突出显示文本[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一项任务是重新创建 unix cal 程序 除了一部分之外 相当简单 今天 它突出显示了该数字 我不知道该怎么做 关于如何在 Ja
  • 如何将现有的 SQLite3 数据库导入 Room?

    好吧 我在桌面上使用 SQLite3 创建了一个只需要读取的某些信息的数据库 我正在制作的应用程序不需要在此表中插入或删除信息 我在 Room 数据库层上做了相当多的谷歌搜索 所有文档都需要在构建应用程序时在 Room 中创建一个新的数据库
  • OpenNLP 与斯坦福 CoreNLP

    我一直在对这两个包进行一些比较 但不确定该往哪个方向走 我简单地寻找的是 命名实体识别 人 地点 组织等 性别识别 一个不错的训练 API 据我所知 OpenNLP 和斯坦福 CoreNLP 提供了非常相似的功能 然而 Stanford C
  • Kafka Java Consumer 已关闭

    我刚刚开始使用卡夫卡 我面临着消费者的一个小问题 我用Java写了一个消费者 我收到此异常 IllegalStateException 此消费者已关闭 我在以下行中遇到异常 ConsumerRecords
  • 当 JMS Prod 位于辅助 POJO 类中时,如何在事务中包含 JMS Producer

    简短的问题 有没有办法强制无状态 EJB 调用的 POJO 存在于 EJB 的上下文中 以便事务和资源注入可以在 POJO 中工作 具体来说 在我想要做的事情的上下文中 如何在 EJB 的事务中包含 POJO JMS 生产者 该生产者在调用
  • Android volley使用RequestFuture.get()时出现超时异常

    在我的片段中 我尝试使用 TMDB 的开放电影数据库来获取有关 正在播放 电影的详细信息 如果我使用 RequestFuture get time TimeUnit 方法来执行此齐射请求 我总是会收到超时错误 如果我在 Safari 中手动
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • 是否有最新的 Facebook Java SDK? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 好像没找到最近更新的 如果没有 是否有一个好的 Java 库来执行与 Facebook 的 API 交
  • 配置jmxremote时无法正常停止tomcat

    我添加了一个jmxremotecatalina bat中的配置 set JAVA OPTS Dcom sun management jmxremote port 9004 Dcom sun management jmxremote ssl
  • 传递 Android DialogFragment 参数时,onCreateDialog 捆绑参数意外为 null

    我正在尝试使用 DialogFragment 在 Android 中显示一个基本对话框 并使用对话框消息的参数 如中所述StackOverflow线程 https stackoverflow com questions 15459209 p
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • java中的预增量/后增量

    有人可以帮助我理解为什么 int i 1 int j 1 int k 1 int l 1 System out println i i System out println j j System out println k k System
  • 在 Qt 中构建 Android 项目不再有效

    所以我对 Android SDK NDK 和 Apache Ant 进行了一些更新 现在我无法构建任何 Android 项目 我收到一条警告 然后它说找不到 build xml 文件 错误 Warning Android platform
  • 如何使用注释处理 Hibernate 和 Spring 中的连接查询?

    我正在使用 Spring 和 Hibernate 以及 MySQL 开发应用程序 我是 Hibernate 新手 完成了基本任务 现在我需要在选择查询中应用联接以使用注释从多个表中获取数据 我已经搜索过但仍然没有任何想法 这是我的数据库表和
  • @Embeddable 中的 @GenerateValue

    我已将实体的 id 分离到一个单独的 Embeddable 类中 该实体如下 Entity Table name users public class Users EmbeddedId private Users pk id private
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时

随机推荐

  • 机器学习 数据的采集和清洗

    本人找到了一条路 不知道对错的路 采集训练的 数据和清理数据 第一步 采集 涉及到如何利用爬虫采集网页csv文件 数据是在UCI 上的 UCI官网如下http archive ics uci edu ml index php 就拿里面最热门
  • java字典树(前缀树) - Kaiqisan

    大家好 都吃晚饭了吗 我是Kaiqisan 是一个已经走出社恐的一般生徒 这一篇文章咱来讲讲字典树把 之前在给别人代答辩数据结构的时候初次了解到这个概念 今天在刷算法课的时候右看到了 所以就有了这个视频 首先还是明确一个概念 什么是字典树
  • 微软Hyper-V虚拟机复制实现双机备份过程

    这个方案是通过hyper v的虚拟机复制功能实现 该方案需要至少两台安装了hyper v功能的服务器 只需在其中一台安装虚拟机系统 另一台虚拟机服务器作为副本接收服务器 部署过程如下 1 比如有两台pc 下面称为pc1 pc2 pc1上面的
  • NodeJS的os模块

    附录 常用HTTP响应头和请求头信息对照表 Node简介 第一个node程序 module 模块系统 npm包管理器 模块系统优先级 认识http内置模块 url内置模块 path内置模块 fs内置模块 http模块服务端进阶 http报文
  • 区块链学习笔记(四)【Merkle树】

    一 字典树 字典树的三个基本特征 1 根节点不包含字符 为空 除根节点外每一个节点只包含一个字符 2 从根节点到某一个节点 路径上经过的字符连接起来 就是该节点对应的字符串 3 每个节点包含的所有子节点的字符都不相同 优势 相比较于哈希表
  • 云计算基础教程(第2版)笔记——基础篇与技术篇介绍

    文章目录 前言 第一篇 基础篇 一 绪论 1 1 云计算的概念以及特征 1 1 1云计算的基本概念 1 1 2云计算的基本特征 1 2 云计算发展简史 1 3 三种业务模式介绍 1 基础设施即服务 IaaS 2 平台即服务 PaaS 3 软
  • leetcode-每日一题2022.3.17 词典中最长的单词

    题目 力扣 思路 模拟 先把words中的字符串放到哈希表里 再遍历words的每一个字符串 判断它从0开始的每一个子串是否存在于哈希表里 代码 class Solution public string longestWord vector
  • 【验证小白】只有SV+modelsim学验证(4)——想办法合理的结束仿真后,准备好了所有代码

    前言 把checker加入到环境中后 环境组件基本就搭建完成了 试着跑了跑出了发现之前的pkt data有一些问题外 还发现仿真结束机制太不合理了 过于简单粗暴 于是把结束仿真的行为梳理一下 做的更合理一些 参考了VMM的思路 做一个漏洞百
  • nginx只允许域名访问的配置方法(ngnix禁止IP访问的配置方法)

    1 只允许域名访问的配置方法一 修改配置文件 判断是否用域名访问 server listen 8081 server name www tq com if host www tq com return 403 2 只允许域名访问的配置方法二
  • HCIP第十一次作业-MPLS

    实验要求及拓扑图 第一步 配IP地址 按要求1配就行 第二步 在R2 R7上起OSPF协议 并把用户环回口改为广播 查看表 第三步 在R2 R7上起MPLS协议 查看表 第四步 在R2 R5 R7上起BGP协议且建邻 在华为设备上还要开启
  • 61-C语言-小猴吃桃问题

    问题 猴桑第一天兴高采烈地采了好多桃子 并且吃了一半 太好吃了 然后又多吃了一个 第二天又吃了一半多一个 以此类推 到第十天的时候 再想吃的时候就剩下1个桃子了 那么请问 第一天猴桑摘了多少桃子 思路 跟做数学题一样 先提取有用条件 1 到
  • 光功率和光衰的单位_太阳能照明的功率、流明与照度的计算方法

    今天小编来给大家聊一聊太阳能照明应用中的一些实际问题 我们经常会收到这样的问题 我的院子100个平方 要选多大功率的太阳能灯 分别要多少个才够亮 本公司印度某地工程项目 这里有一个比较简单的估算公式推荐给大家 首先我们确定自已想要达到一个什
  • python怎么装_python如何安装pickle

    pickle是python语言的一个标准模块 安装python后已包含pickle库 不需要单独再安装 pickle模块实现了基本的数据序列化和反序列化 推荐学习 Python视频教程 通过pickle模块的序列化操作我们能够将程序中运行的
  • 大数据毕设项目 大数据实时疫情数据可视化系统 - flask python

    文章目录 1 课题背景 2 数据库设计实现 3 实现效果 4 Flask框架 5 爬虫 6 Ajax技术 7 Echarts 8 最后 1 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业
  • 使用pytorch版faster-rcnn训练自己数据集

    使用pytorch版faster rcnn训练自己数据集 引言 faster rcnn pytorch代码下载 训练自己数据集 接下来工作 参考文献 引言 最近在复现目标检测代码 师兄强烈推荐FPN 但本文只针对Faster RCNN 大家
  • 小程序swiper动态数据不显示

    情景一 swiper的current不在第一页了 导致第一页的数据看不到 处理方法 在请求数据的时候重置current为0 即
  • C语言printf和scanf函数

    最近在敲c语言例子的时候 对于很多小知识点不清楚 这里主要根据例子来总结一下 一 printf函数 1 printf是格式输出函数 它的作用是想终端输出若干个任意类型的数据 一般格式如下 printf 格式控制 输出表列 例如 printf
  • (Java 基础知识) Java线程池

    ExecutorService 建立多线程的步骤 1 定义线程类 class Handler implements Runnable 2 建立ExecutorService线程池 ExecutorService executorServic
  • 配置logback 不打印日志

    今天尝试下logback 做测试
  • 【C++】 Qt-事件(下)(事件过滤、自定义事件)

    文章目录 事件过滤 自定义事件 事件过滤 event 函数是一个protected的函数 这意味着我们要想重写event 必须继承一个已有的组件类 重写其event 函数 event 函数的确有一定的控制 不过有时候我的需求更严格一些 我希