Qt-事件(下)(事件过滤、自定义事件)

文章目录

      • 事件过滤
      • 自定义事件

事件过滤

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 下 -120qDebug() << "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);  //停止定时器}
}

这样就可以了

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

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

相关文章

【K8S系列】深入解析K8S调度

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 Kubernetes (k8s) 是一个容器编…

Erupt框架学习

Erupt框架学习 Erupt框架Erupt简介学习EruptEruptFieldErupt的逻辑删除Erupt的自定义按钮多数据源配置 Erupt框架 Erupt简介 最近因为工作所以接触到了一个低代码框架Erupt。这是一个通用的配置管理框架&#xff0c;主打就是零前端代码&#xff0c;急速开发通用管理框架。 Er…

Linux常用命令【多图预警】

Linux常用命令 文章目录 Linux常用命令Linux虚拟机的安装Linux系统目录结构Linux命令的语法基础命令查看当前目录下所有子目录和子文件ls查看命令手册man查看当前目录pwd切换到指定目录cd 管道符 |文件目录操作命令创建一级目录&#xff08;文件夹&#xff09;mkdir创建多级目录…

【Servlet学习二】Servlet原理(Tomcat) ServletAPI

目录 &#x1f31f;一、Servlet运行原理 &#x1f308;1、Servlet的执行原理&#xff08;重点&#xff09; &#x1f308;2、Tomcat伪代码的简单理解 2.1 Tomcat初始化流程 2.2 Tomcat处理请求流程 2.3 Servlet 的 service 方法的实现 &#x1f31f;二、Servlet API 详…

Flutter基础布局

Column:纵向布局 Column相当于Android原生的LinearLayout线性布局。 主要代码&#xff1a; class MyHomePage extends StatelessWidget {const MyHomePage({Key? key}) : super(key: key);overrideWidget build(BuildContext context) {return Container(width: double.infi…

深脑接口 | 清华大学李路明团队NSR综述

更多脑机接口前沿技术&#xff0c;关注公众号&#xff1a;脑机接口社区 如何让机器与人类的大脑深处实现交互&#xff1f;清华大学李路明教授研究团队在《国家科学评论》&#xff08;National Science Review, NSR&#xff09;发表综述文章&#xff0c;介绍深脑接口&#xff0…

MMaction2 使用记录1——训练及测试

目录 训练及测试 Training 在你的 PC上训练 Training 多 GPUs Test 训练及测试 Training 在你的 PC上训练 你可以使用tools/train.py在一台有CPU和可选GPU的机器上训练一个模型。 下面是该脚本的完整用法&#xff1a; python tools/train.py ${CONFIG_FILE} [ARGS] 默…

蓝桥杯专题-试题版含答案-【猴子吃桃问题】【小光棍数】【九九乘法表】【谁是最好的Coder】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

快速入门uniapp——从环境搭建到项目实践

&#x1f642;博主&#xff1a;小猫娃来啦 &#x1f642;文章核心&#xff1a;快速入门uniapp——从环境搭建到项目实践 文章目录 初步介绍UniApp开发环境搭建下载和安装UniApp开发工具创建新项目&#xff08;HBuilderX&#xff09;开发工具界面介绍 UniApp基础知识页面结构页面…

linux入门进程概念中(僵尸进程,孤儿进程,进程优先级,并行和并发,环境变量)

目录 一、进程状态 1.看看Linux Kernel怎么说 1.1阻塞 2.进程状态查看 3.僵尸进程 3.1模拟僵尸进程的实验 3.2僵尸进程的危害 4.孤儿进程 4.1模拟孤儿进程实验 二、进程优先级 三、环境变量 3.1常见环境变量 3.2查看环境变量的方法&#xff1a; 3.3 加入环境变量 …

JAVA开发与运维(怎么通过docker部署微服务jar包)

目标&#xff1a; 通过docker的方式部署微服务。 一、背景&#xff1a; 我们通过java开发的微服务可以打成jar包&#xff0c;我们可以直接通过裸机部署&#xff0c;也可以通过docker来部署&#xff0c;本文介绍通过docker来部署微服务。 二、首先我们介绍一下docker的发展过程…

LLM应用的技术栈与设计模式详解

大型语言模型是构建软件的强大新原语。 但由于它们是如此新&#xff0c;并且其行为与普通计算资源如此不同&#xff0c;因此如何使用它们并不总是显而易见的。 在这篇文章中&#xff0c;我们将分享新兴 LLM 应用程序的参考架构。 它展示了我们所见过的人工智能初创公司和先进科…