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

news2024/11/24 20:55:33

文章目录

      • 事件过滤
      • 自定义事件

事件过滤

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);  //停止定时器
    }
}

这样就可以了

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

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

相关文章

使用Python+Autogluon对“员工自评”进行机器学习建模分析

建模核心代码 #员工自评AutoML from autogluon.tabular import TabularDataset, TabularPredictor import warnings warnings.filterwarnings(ignore) train_data TabularDataset(train_df2)# 预测标签 label 员工自评# 模型保存文件名 save_path ../data/AUO-train/model/…

一种快速拓扑聚类算法

使用场景&#xff0c;节点编号不重叠&#xff0c;可以缺损&#xff0c;确定每个节点的相互关系和最大的节点编号&#xff0c;对节点进行聚类。如下图所示&#xff0c;分三个簇&#xff0c;计算每个簇包含的元素。 插入代码&#xff0c;暂时没有继续优化的空间 // TopologicalC…

嵌入式软件开发面试题(一)

目录 1.用预处理指令表示一年有多少秒 2.写出float x 与“零值”比较的if语句 3.为什么说if(0x)比if(x0)好? 4.将地0x8000中存放的整形变量&#xff0c;清除bit1。 5.linux下用shell命令在当前目录下创建myfolder目录&#xff0c;并将此目录的权限设为拥有者可读写群组和…

携手共赢!润建股份与科士达达成战略合作

7月4日&#xff08;今日&#xff09;&#xff0c;润建股份有限公司&#xff08;以下简称”润建股份“&#xff09;与深圳科士达科技股份有限公司&#xff0c;在科士达光明工业园正式签署战略合作框架协议&#xff0c;双方将发挥各自领域的技术优势&#xff0c;在新能源与数字科…

Android开发之屏幕尺寸的兼容

屏幕尺寸和密度 本部分提供了具有特定屏幕配置&#xff08;由屏幕尺寸和密度定义&#xff09;的设备的相对数量数据。为了简化针对不同屏幕配置设计界面的过程&#xff0c;Android 将实际屏幕尺寸和密度的范围划分为多个区间&#xff08;如下表所示&#xff09;。 ldpi mdpitv…

MySQL之数据库引擎详解(内附面试题:InnoDB和MyISAM的联系与区别)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于MySQL数据库引擎的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. 数据库引擎是什么&#xff…

【kubernetes系列】Kubernetes之生命周期和重启策略

概述 Pod 遵循一个预定义的生命周期&#xff0c;起始于 Pending 阶段&#xff0c;如果至少 其中有一个主要容器正常启动&#xff0c;则进入 Running&#xff0c;之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。 在 Pod 运行期间&#xff0c;k…

(30)精准降落和悬停(IRLock)

文章目录 30.1 概述 30.2 哪里可以买到 30.3 连接到自动驾驶仪 30.4 安装到框架上 30.5 通过任务规划器进行设置 30.6 飞行和测试 30.1 概述 Copter 支持使用 IR-LOCK 传感器(IR-LOCK sensor)和声纳或激光雷达(sonar or lidar)进行精确着陆。使用该系统&#xff0c;当飞行…

畅谈RocketMQ重复消费7个根源问题

在众多关于MQ的面试八股文中有这么一道题&#xff0c;“如何保证MQ消息消费的幂等性”。 为什么需要保证幂等性呢&#xff1f;是因为消息会重复消费。 为什么消息会重复消费&#xff1f; 明明已经消费了&#xff0c;为什么消息会被再次被消费呢&#xff1f; 不同的MQ产生的…

0基础学习VR全景平台篇 第56篇:专业版功能-故事线

功能位置示意 一、本功能将用在哪里&#xff1f; 故事线功能&#xff0c;支持将多个VR视频片段&#xff0c;自由设置剧情&#xff0c;在故事中设置多个路线结局&#xff0c;实现VR视频创作新玩法。 区别传统VR视频单项输出内容&#xff0c;促使用户主动思考&#xff0c;参与剧…

windows、linux部署seata1.3.0

前提:https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明Spring Cloud AlibabaSpring CloudSpring BootNacosSeata2.2.7.RELEASESpring Cloud Hoxton.SR122.3.12.RELEASE2.0.31.3.0背景:seata配合nacos使用,并开启nacos,nacos使用默认的namespace,mysql5.7 s…

在Jetpack Compose中使用SurfaceView

在 Android 开发中&#xff0c;SurfaceView 是一种特殊的视图&#xff0c;它拥有自己的专用绘图表面&#xff0c;可以在后台线程中更新&#xff0c;非常适合需要频繁和快速绘制的地方&#xff0c;如游戏和视频播放。然而&#xff0c;在Jetpack Compose&#xff08;Google的新的…

dxf文件怎么转成dwg格式?分享几种简单的转换方法

将DXF文件转成DWG格式可以提高CAD文件的兼容性和功能性&#xff0c;使其更易于在不同的CAD软件之间传输和共享。如果我们需要与其他人共享CAD图纸&#xff0c;或者想要更好地利用CAD编辑软件的各种功能和工具&#xff0c;将文件转换为DWG格式会更好一些&#xff0c;那么怎么进行…

佳明手表APP开发系列02——汉字和图标的标准显示

前言 使用点阵字库的方式来汉化或者增强佳明App的显示是一种传统的方法&#xff0c;操作繁琐&#xff0c;效果也一般。笔者通过进一步的学习&#xff0c;发现佳明的MonkeyC支持一种新的方式&#xff0c;即 BmpFont文件的显示&#xff0c;可以像使用普通字符一样对包括汉字在内…

东芝光电耦合器TLP152(TPL,E的工作原理以及应用

东芝深力科TLP152(TPL,E是SO6封装中的光电耦合器&#xff0c;由GaA组成ℓ作为红外发光二极管&#xff08;LED&#xff09;光学耦合到集成的高增益、高速光电探测器IC芯片。光电探测器IC芯片具有内部屏蔽&#xff0c;提供20kV的高共模瞬态抗扰度/s&#xff0c;从而在输入和输出引…

MySQL-分库分表详解(二)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

港联证券|利好刺激创新药板块迎久违拉升 估值处历史低位

昨日&#xff0c;国家医保局就《谈判药品续约规则》及《非独家药品竞价规则》公开征求意见。在此利好消息影响下&#xff0c;创新药板块集体拉升。截至收盘&#xff0c;创新药指数涨幅近1%&#xff0c;实现四连阳。港股创新药指数收盘涨超3%。 机构认为政策利好创新药发展 《非…

Impala3.4源码阅读笔记(一)data-cache功能

前言 本文为笔者个人阅读Apache Impala源码时的笔记&#xff0c;仅代表我个人对代码的理解&#xff0c;个人水平有限&#xff0c;文章可能存在理解错误、遗漏或者过时之处。如果有任何错误或者有更好的见解&#xff0c;欢迎指正。 基本信息 data-cache是impala在本地的数据缓…

解决github无法打开问题

第一步&#xff0c;去如下目录复制hosts文件副本到桌面【切记&#xff0c;要复制到其他文件夹下&#xff0c;不要直接改原文件】。 C:\Windows\System32\drivers\etc 第二步&#xff0c;以文本文档形式打开复制的副本文件&#xff0c;添加如下语句保存后【替换】掉原有hosts文件…

Ubuntu 16.04 安装Arduino ESP32开发环境记录

文章目录 安装arduino开发环境&#xff1a;安装ESP32开发环境编译上传 安装arduino开发环境&#xff1a; Arduino IDE 2.x好像对于ubuntu16.04不太支持&#xff0c;尝试了一下执行不了。这里 我们可以下载早期的1.8.x版本。 根据自己的电脑类型在红框中选择对应的版本进行下载…