【C++】 Qt-事件(上)(事件、重写事件、事件分发)

文章目录

      • 事件
      • 重写事件
      • 事件分发

事件

事件(event)是由系统或Qt本身在不同的时刻发出的。比如,当用户按下鼠标,敲下键盘,或窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件是在对用户操作做出响应的时候发出,如键盘事件等;另一些事件则是由系统自动发出,如定时器事件(在我们之前写的游戏壳子中用的就是这类事件)。

Qt的事件和信号槽很容易混淆,事件其实也就是所谓的事件驱动,signal由具体对象发出,然后会马上交给connect函数连接的slot进行处理。而对于事件,Qt使用一个**事件队列(windowSystemEventQueue)**对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部,前一个事件完成后,取出后面的事件进行处理。但是,必要的时候,Qt的事件也是可以不进入事件队列,而是直接处理的。

如果我们使用组件,我们关心的是信号槽;如果我们自定义组件,我们关心的是事件。

重写事件

一般我们重写某个组件的事件,需要自定义类,继承对应的组件类,重写感兴趣的事件。

新建子类:

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

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

然后在代码创建成功后将父类改为QLable。

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

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

想知道有哪些事件,我们需要转到父类中,模糊搜索event,事件多为虚函数,供我们重写,定义自己的实现规则。

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

我们关注鼠标相关的事件:分别将mousePressEvent,mouseMoveEvent,mouseReleaseEvent三个虚函数(在qt中表现为斜体)重写。

可以在函数的声明后面加上宏Q_DECL_OVERRIDE或关键字override进行校验当前的虚函数是否为重写父类的,如果不是则会报错。

在重写的三个虚函数中,我们需要跟踪鼠标左键在Lable组件的状态。

声明:

public:void mousePressEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;void mouseMoveEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;void mouseReleaseEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;

定义:

void MyLabel::mousePressEvent(QMouseEvent *ev){if(ev->button() == Qt::LeftButton){  //如果按下的键是鼠标左键this->setText(QString("鼠标左键按下:%1,%2").arg(ev->x()).arg(ev->y()));}
}//button:触发当前事件的按钮
//buttons:触发当前事件时,有哪些按键是按下的
void MyLabel::mouseMoveEvent(QMouseEvent *ev){if(ev->buttons() == Qt::LeftButton|Qt::RightButton){  //鼠标左键和右键同时按下且移动this->setText(QString("鼠标左键合右键同时按下且移动"));}else if(ev->buttons() == Qt::NoButton){  //鼠标移动,没有按下任何的按键this->setText(QString("鼠标移动:%1,%2").arg(ev->x()).arg(ev->y()));}
}void MyLabel::mouseReleaseEvent(QMouseEvent *ev){if(ev->button() == Qt::RightButton){  //鼠标右键抬起this->setText(QString("鼠标右键抬起:%1,%2").arg(ev->x()).arg(ev->y()));}
}

自定义的MyLabel类与主窗口上的Label组件绑定。

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

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

然后我们测试,经过测试我们发现基本都能通过,唯有一个当鼠标只移动没按下时没有反应,这是因为我们在他未按下时没有对他进行追踪,所以我们在构造函数中去添加一个函数。

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

这样就可以了

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

事件分发

事件对象创建完毕后,Qt将这个事件传递给QObject::event()函数,event()函数主要用于事件的分发,一般情况下并不直接处理事件,而是将这些事件按照他们不同的类型,分发给不同的事件处理器(event handler)。

如果想在事件分发之前做一些额外的操作或屏蔽掉某些事件,我们也可以重写event()函数。通过event->type()来确定事件的类型。

举例:在窗口添加组件line edit,我们约定其为电话号码,并且只能输入数字最多可输入11位。

这个需求不敢说用信号槽一定不能做,但是一定会很麻烦,所以我们可以在事件分发中去做

我们首先还是要去自定义类,去继承对应的组件类

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

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

现在类建完了,那么就要去找需要重写的函数了

我们去父类中去通过模糊搜索event事件,找到我们需要的相关事件

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

将这个事件粘贴到子类中,然后我们还需要找到键盘释放的事件,但我们发现父类中没有,所以我们去爷爷类中寻找

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

我们找到了键盘释放函数,并且还找到了一个事件分发函数,将这两个函数也放到子类中去重写

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

然后将这三个函数在源文件中去定义

事件分发是在事件处理器之前发生的,用来集中接收并分发各种类型的事件

在事件分发函数中去实现拦截非法字符

//事件分发,集中接收并分发各种类型的事件
bool MyLineEdit::event(QEvent *event){if(event->type() == QEvent::KeyPress){  //判断事件类型,如果是键盘按下的事件QKeyEvent * pkey=(QKeyEvent *)event;  //已经做判断了,所以可以强转为具体的事件了if(Qt::Key_0 <= pkey->key() && pkey->key() <= Qt::Key_9 || pkey->key() == Qt::Key_Backspace){  //0~9分发,return QLineEdit::event(event);  //调用父类的分发}else{  //不分发qDebug()<<"event 拦截"<<pkey->key();//return true;  //代表的是:当前事件已经被处理,不需要分发了return false;  //代表:当前事件处理不了,一般会转到父窗口处理}}return QLineEdit::event(event);  //其他类型的事件,仍要继续分发
}

然后要将line edit提升为MyLineEdit

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

然后在键盘按下事件中实现将接收到的数字转为字符串,并显示

此时我们在输入电话号时就只能输入数字了,如果输入字母就会被拦截(英文模式下)

将电话号码存放到类成员属性中

我们再加一个限定条件,让输入的字符串只能小于11位

但是还有一个问题,如果我们输入的电话号码有误,那我们不管点什么都会被拦截,所以要再事件分发函数拦截条件中释放一个删除的口子

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

然后在键盘按下函数中做一个判断,如果按下的是退格键,就在结尾删除一位

到现在还没有结束,我们的需求又增加了,为了提高私密性,我们想将中间的四位数字以*的形式显示

所以还要在判断中加上三组判断,如果size小于3就正常输出,如果大于3小于7就显示*,最后大于七位就将前三位正常截取,然后拼接四个 *,在拼接上最后四位,最后再去显示

当然在之前实现尾删除时,最终显示也要显示带*的号码

键盘按下事件的完整实现:

void MyLineEdit::keyPressEvent(QKeyEvent * pkey){if(pkey->key() == Qt::Key_Backspace){  //结尾删除一位m_tel= m_tel.left(m_tel.size()-1);  //保留前面,去除最后一位//this->setText(m_tel);this->setText(this->text().left(this->text().size()-1));}else if(m_tel.size()<11){m_tel += QString::number(pkey->key()-Qt::Key_0);this->setText(m_tel);  //将接收到的数字转换为字符串,并显示if(m_tel.size()<=3){this->setText(m_tel);}else if(3<m_tel.size() && m_tel.size() <=7){QString tel = m_tel.left(3);for(int i=3;i<m_tel.size();i++){tel+="*";}this->setText(tel);}else{QString tel = m_tel.left(3)+"****"+ m_tel.right(m_tel.size()-7);this->setText(tel);}}
}

最后还剩一点,我们此时的电话号码是带*加密的状态,那么我们想把键盘释放事件也利用上,在键盘释放中实现将完整电话号码显示出来,我们约定在回车键抬起时弹出一个弹出框将完整电话号码显示出来

void MyLineEdit::keyReleaseEvent(QKeyEvent *event){//Qt::Key_Return 字母区的回车  Qt::Key_Enter 数字小键盘的回车if(event->key() == Qt::Key_Return){  //如果是回车抬起QMessageBox::information(this,"电话号码",m_tel);}
}

最后,我们还记得之前在输入字母时会默认是中文,如果是中文输入法那么就不会对字母拦截,所以我们想把中文输入法禁用

在构造函数初始时调用一个禁用中文输入法的函数

MyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent)
{this->setAttribute(Qt::WA_InputMethodEnabled,false);  //禁用中文输入法
}

最终窗口显示

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

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

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

相关文章

Leetcode---351周赛

周赛题目 2748. 美丽下标对的数目 2749. 得到整数零需要执行的最少操作数 2750. 将数组划分成若干好子数组的方式 2751. 机器人碰撞 一、美丽下标对的数目 这题没什么好说的&#xff0c;按照题目的要求直接暴力求解&#xff0c;代码如下 bool gcd(int x,int y){if(x1||y1)…

钡铼技术多功能RTUS475:稳定可靠的油田数据采集解决方案

标题&#xff1a;S475在油田数据采集中的应用 摘要&#xff1a;本文介绍了钡铼技术多功能RTUS475在油田数据采集中的应用。该设备基于高性能微处理器MCU和嵌入式实时操作系统&#xff0c;支持Modbus Slave和Modbus Master功能&#xff0c;并能通过无线网络实现短信报警和数据传…

Springboot项目使用原生Websocket

目录 1.启用Websocket功能2.封装操作websocket session的工具3.保存websocket session的接口4.保存websocket session的类5.定义websocket 端点6.创建定时任务 ping websocket 客户端 1.启用Websocket功能 package com.xxx.robot.config;import org.springframework.context.a…

机器学习优化器和SGD和SGDM实验对比(编程实现SGD和SGDM)

机器学习优化器和SGD和SGDM实验对比 博主最近在学习优化器&#xff0c;于是呢&#xff0c;就做了一个SGD和SGDM的实验对比&#xff0c;可谓是不做不知道&#xff0c;一做吓一跳&#xff0c;这两个算法最终对结果的影响还是挺大的&#xff0c;在实验中SGDM明星要比SGD效果好太多…

springBoot配置多环境

在代码中一般有3个环境&#xff0c;为了避免频繁的每次上线需要手动更改环境的问题。 test 本地测试环境&#xff0c;代码调试的 dev 服务端开发环境-用来验证用 prod 服务端正式环境 我创建2个做示例&#xff0c;里面写的不同配置 点运行的项目会有一个Edit Configurations…

​浅谈大型语言模型

大型语言模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;是一类强大的人工智能模型&#xff0c;具有出色的自然语言处理能力。它们在许多任务中表现出色&#xff0c;如机器翻译、文本摘要、对话生成和情感分析等。下面我们将介绍大型语言模型的训练和生成过…

智谱AI-算法实习生(知识图谱方向)实习面试记录

岗位描述 没错和我的经历可以说是match得不能再match了&#xff0c;但是还是挂了hh。 面试内容 给我面试的是唐杰老师的博士生&#xff0c;方向是社交网络数据挖掘&#xff0c;知识图谱。不cue名了&#xff0c;态度很友好的 &#xff0c;很赞。 date&#xff1a;6.28 Q1 自…

【码银送书第一期】通用人工智能:初心与未来

目录 前言 正文 内容简介 作者简介 译者简介 目录 前言 自20世纪50年代图灵在其划时代论文《计算机器与智能》中提出“图灵测试”以及之后的达特茅斯研讨会开始&#xff0c;用机器来模仿人类学习及其他方面的智能&#xff0c;即实现“人工智能”&#xff08;Artificial …

ORA-31664: unable to construct unique job name when defaulted

某个环境备份不足空间问题处理后&#xff0c;手动执行expdp备份的脚本&#xff0c;报错如下 Export: Release 11.2.0.4.0 - Production on Tue Jul 4 11:46:14 2023 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle D…

获取移动设备的电池信息

通过BatteryManager来获取关于电池的信息 实例 package com.example.softwarepatentdemo;import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManag…

2023年大学计算机专业实习心得14篇

2023年大学计算机专业实习心得精选篇1 20__年已然向我们挥手告别而去了。在20__年初之际&#xff0c;让我们对过去一年的工作做个总结。忙碌的一年里&#xff0c;在领导及各位同事的帮助下&#xff0c;我顺利的完成了20__年的工作。为了今后更好的工作&#xff0c;总结经验&…

Docker|kubernetes|本地镜像批量推送到Harbor私有仓库的脚本

前言&#xff1a; 可能有测试环境&#xff0c;而测试环境下有N多的镜像&#xff0c;需要批量导入到自己搭建的Harbor私有仓库内&#xff0c;一般涉及到批量的操作&#xff0c;自然还是使用脚本比较方便。 本文将介绍如何把某个服务器的本地镜像 推送到带有安全证书的私有Harb…