【Qt】消息机制和事件

文章目录

  • 事件
  • event()
  • 事件过滤器
  • 案例:检测鼠标事件
  • 案例:定时器

事件

事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件

一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件


回顾

Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数,这个函数就是开始 Qt 的事件循环,在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。

当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent,在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数


event()

event()函数主要用于事件的分发,所以如果希望在事件分发之前做一些操作,就可以重写这个event()函数

  • 如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false
  • 如果返回值是 true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件,并且在event()函数中,调用事件对象的accept()和ignore()函数是没有作用的,不会影响到事件的传播

event()函数中实际是通过事件处理器来响应一个具体的事件。这相当于event()函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理器,即可让 Qt 调用我们自己实现的版本。

  • 由此可见,event()是一个集中处理不同类型的事件的地方

事件过滤器

在程序将事件分发到事件分发器前,可以利用过滤器做拦截

QObject有一个eventFilter()函数,用于建立事件过滤器

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

事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果不想让它继续转发,就返回 true,否则返回 false

安装过滤器需要调用QObject::installEventFilter()函数

void QObject::installEventFilter ( QObject * filterObj )

注意事项

1.事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效

2.事件过滤器在目标对象接收到事件之前进行处理,如果我们将事件过滤掉,目标对象根本不会见到这个事件


案例:检测鼠标事件

前置工作

1.项目 => Add New =>C++ class

image-2023100520492631

2.在mianWindow.ui文件当中创建一个Label控件 => 提升为

image-20231005205126983

3.可以更改控件的格式 看的更明显

image-20231005205210158


注意:在第二步当中可以发现:基类名称为 Q L a b e l QLabel QLabel,所以生成的myLabel.h和myLabel.cpp文件要改动:

//.h文件
#include <QLabel>
class myLabel : public QLabel//改为继承QLabel//.cpp文件
myLabel::myLabel(QWidget *parent) : QLabel(parent) //父类对象从QWidget(parent)  =》 QLabel(parent)  

myLabel.h

//鼠标进入事件
void enterEvent(QEvent *event);  //从父类继承的函数//鼠标离开事件
void leaveEvent(QEvent *);//鼠标按下
virtual void mousePressEvent(QMouseEvent *ev);//鼠标释放
virtual void mouseReleaseEvent(QMouseEvent *ev);//鼠标移动
virtual void  mouseMoveEvent(QMouseEvent *ev);//通过event事件分发器 拦截 鼠标按下事件
bool event(QEvent *e);

myLabel.cpp

//鼠标进入事件
void myLabel::enterEvent(QEvent *event)
{qDebug() << "鼠标进入了";
}//鼠标离开事件
void myLabel::leaveEvent(QEvent *)
{qDebug() << "鼠标离开了";
}//鼠标按下
void myLabel::mousePressEvent(QMouseEvent *ev)
{//当鼠标左键按下  提示信息if( ev->button() ==  Qt::LeftButton){//arg:参数  global的含义:基于窗口的距离 普通的x,y:基于控件的距离QString str = QString( "鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());qDebug() << str;}
}//鼠标释放
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{if( ev->button() ==  Qt::LeftButton){QString str = QString( "鼠标释放了 x = %1   y = %2  globalX = %3 globalY "  \"= %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());qDebug() << str;}
}//鼠标移动
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{// 当鼠标左键按下  提示信息  buttons:返回按键类型 ev->buttons() &   Qt::LeftButton:如果是左键才为真if( ev->buttons() &   Qt::LeftButton )  //移动是持续的过程!{QString str = QString( "鼠标移动了 x = %1   y = %2  globalX = %3 globalY " \"= %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());qDebug() << str;}
}bool myLabel::event(QEvent *e)
{//如果是鼠标按下 ,在event事件分发中做拦截操作if(e->type() == QEvent::MouseButtonPress){QMouseEvent * ev  = static_cast<QMouseEvent *>(e); //QEvent是QMouseEvent的父类QString str = QString( "Event函数中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());qDebug() << str;return true; //true代表用户自己处理这个事件,不向下分发 => 不会触发mousePressEvent函数}//其他事件 交给父类处理 =>默认处理return QLabel::event(e);
}

注意:

1.QString的arg()函数可以自动替换掉QString中出现的占位符。其占位符以 % 开始,后面是占位符的位置,例如 %1,%2 这种

QString("[%1, %2]").arg(x).arg(y); =>x替换 %1,y替换 %2  QString为[x, y]

2.要点击鼠标之后才能在 m o u s e M o v e E v e n t mouseMoveEvent mouseMoveEvent函数中显示鼠标坐标值,原因如下:

  • QWidget中有一个mouseTracking属性,该属性用于设置是否追踪鼠标只有鼠标被追踪时,mouseMoveEvent()才会发出。
  • 如果mouseTracking是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()事件如果mouseTracking为 true,则mouseMoveEvent()直接可以被发出。

如果想不点击鼠标也能在 m o u s e M o v e E v e n t mouseMoveEvent mouseMoveEvent函数中显示鼠标坐标值,在构造函数当中:

myLabel::myLabel(QWidget *parent) : QLabel(parent)
{//设置鼠标追踪状态   默认为falsesetMouseTracking(true);
}

3.$ev->button() $可以判断所有按键 Q t : : L e f t B u t t o n Qt::LeftButton Qt::LeftButton Q t : : R i g h t B u t t o n Qt::RightButton Qt::RightButton

e v − > b u t t o n s ( ) ev->buttons() ev>buttons()判断组合按键 判断move时候的左右键 结合 & 操作符


案例:定时器

创建方式1:

利用事件 void timerEvent ( QTimerEvent * ev),启动定时器: s t a r t T i m e r ( 1000 ) startTimer(1000) startTimer(1000) 单位是毫秒,$timerEvent 的返回值是定时器的唯一标示可以和 的返回值是定时器的唯一标示 可以和 的返回值是定时器的唯一标示可以和ev->timerId $做比较

创建方式2:

1.利用定时器类 QTimer => 创建定时器对象 QTimer * timer = new QTimer(this)

2.启动定时器 timer->start(毫秒)

3.每隔一定毫秒发送信号 timeout ,进行监听

4.暂停 : timer->stop


前置内容

1.先预先创建4个 L a b e l Label Label

image-20231006102712863

创建定时器方法1:需要重写定时器的事件

//widget.h
//重写定时器的事件
void timerEvent(QTimerEvent *);int id1; //定时器1的唯一标示
int id2; //定时器2的唯一标示
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//启动定时器  => 会返回定时器的标识符id1 = startTimer(1000); //参数:时间间隔,单位是毫秒id2 = startTimer(2000);
}void MainWindow::timerEvent(QTimerEvent* ev)
{if(ev->timerId() == id1)//label1 每隔1秒+1{static int num = 1;ui->label_1->setText( QString::number(num++));}if(ev->timerId() == id2) //label2  每隔2秒 +1{static int num2 = 1;ui->label_2->setText( QString::number(num2++));}
}

第二种方式创建定时器

在ui界面当中多增加两个按钮用于停止和恢复定时器:

image-20231006104029330

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//定时器第二种方式QTimer * timer = new QTimer(this);//启动定时器timer->start(500);connect(timer,&QTimer::timeout,[=](){   //label3 每隔0.5秒+1static int num = 1;ui->label_3->setText(QString::number(num++));});//点击暂停按钮 实现停止定时器connect(ui->stop_btn,&QPushButton::clicked,[=](){timer->stop();qDebug() <<"定时器已暂停" ;});//点击恢复按钮 重写启动定时器connect(ui->start_btn,&QPushButton::clicked,[=](){timer->start(500);qDebug() <<"定时器已恢复" ;});
}

定时器的事件过滤器

重写 bool eventFilter(QObject *, QEvent *);

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{//步骤1:给控件label_4 安装事件过滤器ui->label_4->installEventFilter(this);
}// 步骤2  重写 eventfilter事件
bool MainWindow::eventFilter(QObject * obj , QEvent * e)
{if(obj == ui->label_4)//控件判断  因为可能很多控件都安装了事件过滤器{if(e->type() == QEvent::MouseButtonPress)//如果是label的鼠标按下{QMouseEvent * ev  = (QMouseEvent*)e;QString str = QString( "事件过滤器中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());qDebug() << str;qDebug() <<"事件过滤器拦截成功";return true; //true代表用户自己处理这个事件,不向下分发}}//其他默认处理return QWidget::eventFilter(obj,e);
}

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

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

相关文章

Docker Swarm 集群搭建

Docker Swarm Mode Docker Swarm 集群搭建 Docker Swarm 节点维护 Docker Service 创建 1.准备主机 搭建一个 docker swarm 集群&#xff0c;包含 5 个 swarm 节点。这 5 个 swarm 节点的 IP 与暂 时的角色分配如下&#xff08;注意&#xff0c;搭建完成后会切换角色&#xff…

Linux绝对路径和相对路径

在 Linux 中&#xff0c;简单的理解一个文件的路径&#xff0c;指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置&#xff0c;那么它就可以找到这个文件。指明一个文件存放的位置&#xff0c;有 2 种方法&#xff0c;分别是使用绝对路径和相对路径。…

​​​​​​​Python---练习:打印直角三角形(利用wihle循环嵌套)

案例&#xff1a; 打印直角三角形&#xff0c;特征&#xff1a;一共有5行&#xff0c;第1行&#xff0c;有1列。第2行&#xff0c;有2列&#xff0c;第3&#xff0c;有3列。 思考&#xff1a; pycharm里面&#xff0c;输出三角形&#xff0c;因为本来控制台就是长方形&#…

Python桌面应用之XX学院水卡报表查询系统(Tkinter+cx_Oracle)

一、功能样式 Python桌面应用之XX学院水卡报表查询系统功能&#xff1a; 连接Oracle数据库&#xff0c;查询XX学院水卡操作总明细报表&#xff0c;汇总数据报表&#xff0c;个人明细报表&#xff0c;进行预览并且支持导出报表 1.总明细报表样式 2.汇总明细样式 3.个人明细…

硬件信息查看工具 EtreCheckpro mac中文版功能介绍

etrecheckpro mac中文版是一款专业的硬件信息查看工具&#xff0c;它能够快速的检测Mac电脑的软硬件信息&#xff0c;加强用户对自己计算机的了解&#xff0c;EtreCheckPro for Mac下载首先会对电脑的软硬件信息进行扫描收集&#xff0c;之后才会显示出来。EtreCheck Mac版报告…

Python深度学习进阶与应用丨注意力(Attention)机制、Transformer模型、生成式模型、目标检测算法、图神经网络、强化学习详解等

目录 第一章 注意力&#xff08;Attention&#xff09;机制详解 第二章 Transformer模型详解 第三章 生成式模型详解 第四章 目标检测算法详解 第五章 图神经网络详解 第六章 强化学习详解 第七章 深度学习模型可解释性与可视化方法详解 更多应用 近年来&#xff0c;伴…

mac安装+配置python3环境

一、python3下载 官网下载 https://www.python.org/ 二、python3安装 打开下载好的.pkg文件一直继续确认即可。 三、验证是否安装成功 打开终端&#xff0c;输入python3&#xff0c;如果返回python对应的版本信息&#xff0c;则安装成功。 四、python配置 如果需要输入…

`SQL`编写判断是否为工作日函数编写

SQL编写判断是否为工作日函数编写 最近的自己在写一些功能,遇到了对于工作日的判断,我就看了看sql,来吧!~(最近就是好疲惫) 我们一起看看(针对ORACLE) 1.声明: CREATE OR REPLACE PACKAGE GZYW_2109_1214.PKG_FUN_GETDAY_HDAY AS /** * 通过节假日代码获取指定的日期[查找基…

Synchronized同步锁

synchronized 一&#xff0c;介绍 Java中的synchronized关键字用于实现线程同步&#xff0c;可以修饰方法或代码块。 1. 修饰方法&#xff1a;当一个方法被synchronized修饰时&#xff0c;只有获得该方法的锁的线程才能执行该方法。其他线程需要等待锁的释放才能执行该方法。…

Python+requests+pytest+excel+allure 接口自动化测试实战

定义&#xff1a; Unittest是Python标准库中自带的单元测试框架&#xff0c;Unittest有时候也被称为PyUnit&#xff0c;就像JUnit是Java语言的标准单元测试框架一样&#xff0c;Unittest则是Python语言的标准单元测试框架。 Pytest是Python的另一个第三方单元测试库。它的目的…

Linux C语言开发-D2vi编辑器使用

三种模式基础 命令行模式、插入模式和底行模式 :! [命令]&#xff1a;可在命令行模式下执行命令 :w test1.cc可备份当前编辑的文件 :r head.h可为当前文件引入头文件 u&#xff1a;撤销 命令行进入插入模式&#xff1a; i&#xff1a;从当前光标位置之前开始插入 …

Mac 开机提示Google LLC 注册 无法登录进入系统

Google LLC 会在电脑启动时提示如下弹窗&#xff0c;并要求登录谷歌账户进行验证 此时很明显没有用来进行验证的账号&#xff0c;所以需要关掉这个验证程序 从日志里面可以看到LLC启动了一个Tiny.app的程序 只需要想办法把这个程序删掉即可 关机 按住 Command R 开机 进入R…

muduo异步日志库

文章目录 一、日志库模型1.前端 参考 一、日志库模型 组成部分 muduo日志库由前端和后端组成。 muduo日志库是异步高性能日志库&#xff0c;其性能开销大约是前端每写一条日志消息耗时1.0us~1.6us。 采用双缓冲区&#xff08;double buffering&#xff09;交互技术。基本思…

C语言文件操作(1)

C语言文件操作&#xff08;1&#xff09; 文章目录 C语言文件操作&#xff08;1&#xff09;一、理解文件1.概述2.分类①.正常角度②.文本文件和二进制文件 二、文件的打开和关闭1.流和标准流2.文件类型指针3.文件的打开和关闭以及使用类型 三、文件缓冲区 一、理解文件 1.概述…

【CSS】BFC 块级格式化上下文

1. 块级格式化上下文&#xff08;BFC&#xff09; 它是一块独立的渲染区域&#xff0c;规定该区域内&#xff0c;常规流块盒的布局。 先来说一下常规流块盒&#xff1a; 常规流块盒在水平方向上&#xff0c;必须盛满包含块常规流块盒在包含块的垂直方向上依次摆放常规流块盒…

GEO生信数据挖掘(九)肺结核数据-差异分析-WGCNA分析(900行代码整理注释更新版本)

第六节&#xff0c;我们使用结核病基因数据&#xff0c;做了一个数据预处理的实操案例。例子中结核类型&#xff0c;包括结核&#xff0c;潜隐进展&#xff0c;对照和潜隐&#xff0c;四个类别。第七节延续上个数据&#xff0c;进行了差异分析。 第八节对差异基因进行富集分析。…

yolov7改进优化之蒸馏(二)

续yolov7改进优化之蒸馏&#xff08;一&#xff09;-CSDN博客 上一篇已经基本写出来yolov7/v5蒸馏的整个过程&#xff0c;不过要真的训起来我们还需要进行一些修改。 Model修改 蒸馏需要对teacher和student网络的特征层进行loss计算&#xff0c;因此我们forward时要能够返回需…

PyTorch 与 TensorFlow:机器学习框架之战

深度学习框架是简化人工神经网络 (ANN) 开发的重要工具&#xff0c;并且其发展非常迅速。其中&#xff0c;TensorFlow 和 PyTorch 脱颖而出&#xff0c;各自在不同的机器学习领域占有一席之地。但如何为特定项目确定理想的工具呢&#xff1f;本综合指南[1]旨在阐明它们的优点和…

mysql—面试50题—1

注&#xff1a;面试50题将分为5个部分&#xff0c;每部分10题 一、查询数据 学生表 Student create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10)); insert into Student values(01 , 赵雷 , 1990-01-01 , 男); insert into Student …

在Telegram营销后该如何进行客户管理

与目标客户进行接触之后&#xff0c;我们就要开始考虑后续怎么去销售自己的产品。这个过程可能是很漫长的&#xff0c;我们需要经常去联系对方&#xff0c;回答对方的疑问。但是现实中通常一个员工会手握多个账号&#xff0c;很难及时知道每个账号的信息&#xff0c;管理客户成…