【QT】Qt事件

news/2024/9/14 2:03:31/ 标签: qt, 开发语言, c++

目录

前置知识

事件概念

常见的事件描述

进入和离开事件

代码示例: 

鼠标事件

鼠标点击事件

鼠标释放事件 

鼠标双击事件

鼠标滚轮动作

键盘事件

定时器事件

开启定时器事件

窗口相关事件

窗口移动触发事件 

窗口大小改变时触发的事件

扩展


前置知识

        在前面的介绍中,我们知道信号槽就是:用户进行的各种操作,就可能会产生出信号,可以给某个信号指定槽函数,当信号触发时,就能够自动的执行对应的槽函数。

        这里的事件也是类似的,用户进行的各种操作,也会产生事件,程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码。

        事件本身是操作系统提供的机制,Qt也同样把操作系统的事件机制进行了封装,拿到了Qt中,但是由于事件对应的代码编写起来不是很方便,Qt对于事件机制又进行了进一步的封装,就得到了信号槽。

        也就是说,信号槽就是对于事件的进一步封装,事件是信号槽的底层机制

        实际上Qt开发过程中,绝大部分和用户之间进行的交互都是通过“信号槽”,来完成的,有些特殊情况下,信号槽不一定能搞定(某个用户的动作行为,Qt中没有提供对应的信号……)此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑。

事件概念

        事件是应⽤程序内部或者外部产⽣的事情或者动作的统称。在 Qt 中使⽤⼀个对象来表⽰⼀个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本⾝在不同的时刻发出的。当⽤⼾按下⿏标、敲下键盘,或者是窗⼝需要重新绘制的时候,都会发出⼀个相应的事件。⼀些事件是在⽤⼾操作时发出,如键盘事件、⿏标事件等,另⼀些事件则是由系统本⾝⾃动发出,如定时器事件。常⻅的 Qt 事件如下:

常见的事件描述

事件名称描述
⿏标事件
⿏标左键、⿏标右键、⿏标滚轮,⿏标的移动,⿏标按键的按下和松开
键盘事件
按键类型、按键按下、按键松开
定时器事件
定时时间到达
进⼊离开事件
⿏标的进⼊和离开
滚轮事件
⿏标滚轮滚动
绘屏事件
重绘屏幕的某些部分
显⽰隐藏事件
窗⼝的显⽰和隐藏
移动事件
窗⼝位置的变化
窗⼝事件
是否为当前窗⼝
⼤⼩改变事件
窗⼝⼤⼩改变
焦点事件
键盘焦点移动
拖拽事件
⽤⿏标进⾏拖拽

进入和离开事件

这里需要创建QLabel的子类,重写enterEvent和leaveEvent。

注意:要想重写父类的函数,就需要确保这里写的函数名字和函数的参数列表一致(形参名无所谓)

这里要注意,我们通过图形化创建的label是QLabel类的,不是我们创建的子类的实例,我们可以将他提升为Label,也就是我们创建的子类。

此时在看这个控件的类型,可以发现已经变为Label

代码示例: 

label.h

#ifndef LABEL_H
#define LABEL_H
#include <QLabel>
#include <QWidget>class Label : public QLabel
{Q_OBJECT
public:Label(QWidget* parent);void enterEvent(QEvent* event);void leaveEvent(QEvent* event);
};#endif // LABEL_H

label.cpp

#include "label.h"#include <QDebug>
Label::Label(QWidget* parent):QLabel(parent)
{}void Label::enterEvent(QEvent *event)
{(void)event;qDebug()<<"enterEvent"<<endl;
}void Label::leaveEvent(QEvent *event)
{(void)event;qDebug()<<"leaveEvent"<<endl;
}

效果如下:

鼠标事件

鼠标点击事件

mousePressEvent()用法示例:

void Label::mousePressEvent(QMouseEvent *ev)
{//当前event对象就包含了鼠标点击位置的坐标qDebug()<<ev->x()<<','<<ev->y();qDebug()<<ev->globalX()<<','<<ev->globalY();
}

        这个事件处理的是鼠标点击后,显示鼠标点击位置的坐标, 如下所示,返回两个坐标,但是这两个坐标并不相同,因为 ev->globalX()和ev->globalY()返回的是以屏幕左上角为原点的坐标,x()和y()是以label标签左上角为原点的坐标。

         这里的mousePressEvent不仅是左键点击触发,右键和滚轮点击也可触发,有的鼠标还带有前进后退侧键也是可以触发的。 

         我们有时也要区分用户按了什么按钮,因此可以加上一层判断,如下:

    if(ev->button()==Qt::LeftButton){qDebug()<<"按下左键";}else if(ev->button()==Qt::RightButton){qDebug()<<"按下右键";}

鼠标释放事件 

mouseReleaseEvent()用法如下:

void Label::mouseReleaseEvent(QMouseEvent *ev)
{if(ev->button()==Qt::LeftButton){qDebug()<<"释放左键";}else if(ev->button()==Qt::RightButton){qDebug()<<"释放右键";}
}

鼠标双击事件

如果设置了鼠标单击事件,需要注意逻辑处理,只有第二次按下的时候,才能够识别是双击。双击的同时可能会触发单击事件。

void Label::mouseDoubleClickEvent(QMouseEvent *ev)
{if(ev->button()==Qt::LeftButton){qDebug()<<"双击左键";}else if(ev->button()==Qt::RightButton){qDebug()<<"双击右键";}
}

        上述重写鼠标事件的操作,都是在自定义的label中完成的,此时鼠标只有在label范围进行动作,才能捕获到,也可以把这些操作直接放到Widget(QWidget子类)来完成,这样的话,鼠标在整个窗口中进行的各种动作都能获取到了。

        其中鼠标移动不同于鼠标按下,随便移动下鼠标,就会产生大量的鼠标移动事件,当进行捕获事件的时候,尤其是在进行一些复杂逻辑的时候,程序负担就很重,就很容易产生卡顿的情况,

        Qt为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪。也就是说鼠标移动的时候,不会调用mouseMoveEvent,除非显式告诉qt追踪鼠标位置。做法如下:

    this->setMouseTracking(true);

鼠标滚轮动作

通过dalta()方法可以或者滚轮滚动的距离。

void Widget::wheelEvent(QWheelEvent *ev)
{qDebug()<<ev->delta();
}

键盘事件

要想获取到用户的键盘按键,QShortCut这是信号槽机制封装过,获取键盘按键的方式。站在底层的角度,也可以通过事件获取到当前用户键盘按下的情况。

void Widget::keyPressEvent(QKeyEvent *event)
{if(event->key() == Qt::Key_A){qDebug()<<"按下了 A 键";}
}

上述只是获取单个按键,有时候我们需要获取组合键之类的操作,如下 ctrl + a

void Widget::keyPressEvent(QKeyEvent *event)
{if(event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier){qDebug()<<"按下了 ctrl + A 键";}
}

定时器事件

QTimer实现了定时器的功能,在QTimer背后是QTimerEvent定时器事件进行支撑的,QObject提供了一个timerEvent这个函数,startTimer 启动定时器,killTimer关闭定时器。

开启定时器事件

int timerId = this->startTimer(1000);

此处的timerId类似于Linux课堂上谈到的“文件描述符”,起到了身份标识的效果。

使用示例:

#include "widget.h"
#include "ui_widget.h"
#include <QWheelEvent>
#include <QDebug>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);timerId = this->startTimer(1000);
}Widget::~Widget()
{delete ui;
}void Widget::timerEvent(QTimerEvent *event)
{//如果一个程序中存在多个定时器(startTimer 创建的定时器,此时每个定时器都会触发timerEvent函数)//先判断以下这次触发是否是想要的定时器触发的if(event->timerId() != this->timerId){return;}int value = ui->lcdNumber->intValue();if(value <= 0){this->killTimer(this->timerId);return;}value-=1;ui->lcdNumber->display(value);
}

使用timerEvent比QTimer 还是要更复杂一点,手动管理timerId,还需要区分这次调用是哪个timer引起的。

窗口相关事件

窗口移动触发事件 

moveEvent();

const QPoint & oldpos() const;

const QPoint & pos() const;

示例: 

void Widget::moveEvent(QMoveEvent *event)
{qDebug()<<event->oldPos();qDebug()<<event->pos();
}


窗口大小改变时触发的事件

resizeEvent();

void Widget::resizeEvent(QResizeEvent *event)
{qDebug()<<event->size();
}

扩展

事件分发/事件过滤 属于Qt事件机制背后的一些逻辑,事件分发就是重写event函数,直接获取所有事件,这个后续进行介绍。


http://www.ppmy.cn/news/1475607.html

相关文章

Vue3响应系统的作用与实现

副作用函数的执行会直接或间接影响其他函数的执行。一个副作用函数中读取了某个对象的属性&#xff0c;当该属性的值发生改变后&#xff0c;副作用函数自动重新执行&#xff0c;这个对象就是响应式数据。 1 响应式系统的实现 拦截对象的读取和设置操作。当读取某个属性值时&a…

澳门建筑插画:成都亚恒丰创教育科技有限公司

澳门建筑插画&#xff1a;绘就东方之珠的斑斓画卷 在浩瀚的中华大地上&#xff0c;澳门以其独特的地理位置和丰富的历史文化&#xff0c;如同一颗璀璨的明珠镶嵌在南国海疆。这座城市&#xff0c;不仅是东西方文化交融的典范&#xff0c;更是建筑艺术的宝库。当画笔轻触纸面&a…

STM32MP135裸机编程:唯一ID(UID)、设备标识号、设备版本

0 资料准备 1.STM32MP13xx参考手册1 唯一ID&#xff08;UID&#xff09;、设备标识号、设备版本 1.1 寄存器说明 &#xff08;1&#xff09;唯一ID 唯一ID可以用于生成USB序列号或者为其它应用所使用&#xff08;例如程序加密&#xff09;。 &#xff08;2&#xff09;设备…

conda install问题记录

最近想用代码处理sar数据&#xff0c;解放双手。 看重了isce这个处理平台&#xff0c;在安装包的时候遇到了一些问题。 这一步持续了非常久&#xff0c;然后我就果断ctrlc了 后面再次进行尝试&#xff0c;出现一大串报错&#xff0c;不知道是不是依赖项的问题 后面看到说mam…

前端预览图片的两种方式:转Base64预览或转本地blob的URL预览,并再重新转回去

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 预览图片 一般情况下&#xff0c;预览图片功能&#xff0c;是后端返回一个图片地址资源&#xff08;字符串&#xff09;给前端&#xff0c;如&#xff1a;ashuai.work/static…

搜维尔科技:scalefit人体工程学分析表明站立式工作站的高度很重要

搜维尔科技&#xff1a;scalefit人体工程学分析表明站立式工作站的高度很重要 搜维尔科技&#xff1a;scalefit人体工程学分析表明站立式工作站的高度很重要

红酒与未来科技:传统与创新的碰撞

在岁月的长河中&#xff0c;红酒以其深邃的色泽、丰富的口感和不同的文化魅力&#xff0c;成为人类文明中的一颗璀璨明珠。而未来科技&#xff0c;则以其迅猛的发展速度和无限的可能性&#xff0c;领着人类走向一个崭新的时代。当红酒与未来科技相遇&#xff0c;一场传统与创新…

【2024最新】C++扫描线算法介绍+实战例题

扫描线介绍&#xff1a;OI-Wiki 【简单】一维扫描线&#xff08;差分优化&#xff09; 网上一维扫描线很少有人讲&#xff0c;可能认为它太简单了吧&#xff0c;也可能认为这应该算在差分里&#xff08;事实上讲差分的文章里也几乎没有扫描线的影子&#xff09;。但我认为&am…

1.26、基于概率神经网络(PNN)的分类(matlab)

1、基于概率神经网络(PNN)的分类简介 PNN(Probabilistic Neural Network,概率神经网络)是一种基于概率论的神经网络模型,主要用于解决分类问题。PNN最早由马科夫斯基和马西金在1993年提出,是一种非常有效的分类算法。 PNN的原理可以简单概括为以下几个步骤: 数据输入层…

Tomcat的服务部署于优化

一、tomcat是一个开源的web应用服务器&#xff0c;nginx主要处理静态页面&#xff0c;那么静态请求&#xff08;连接数据库&#xff0c;动态页面&#xff09;并不是nginx的强项&#xff0c;动态的请求会交给Tomcat进行处理&#xff0c;tomcat是用java代码写的程序&#xff0c;运…

[leetcode]partition-list 分隔链表

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:ListNode* partition(ListNode* head, int x) {ListNode *smlDummy new ListNode(0), *bigDummy new ListNode(0);ListNode *sml smlDummy, *big bigDummy;while (head ! nullptr) {if (head->val &l…

【数学建模】——【线性规划】及其在资源优化中的应用

目录 线性规划问题的两类主要应用&#xff1a; 线性规划的数学模型的三要素&#xff1a; 线性规划的一般步骤&#xff1a; 例1&#xff1a; 人数选择 例2 &#xff1a;任务分配问题 例3: 饮食问题 线性规划模型 线性规划的模型一般可表示为 线性规划的模型标准型&…

Oracle各种连接写法介绍

1、左连接 左连接&#xff08;左外连接&#xff09;&#xff1a; 基表全部查出来&#xff0c;外连接表有的匹配&#xff0c;没有则为null&#xff1b; 记录数与基表的记录数相同&#xff0c;前提是where后未加条件过滤&#xff1b; 两种写法&#xff08;left join&#xff09…

DP讨论——建造者模式

学而时习之&#xff0c;温故而知新。 敌人出招&#xff08;使用场景&#xff09; 组合关系中&#xff0c;如果要A对象创建B对象&#xff0c;或者要A对象创建一堆对象&#xff0c;这种是普遍的需求。 你出招 这种适合创建者模式&#xff0c;我感觉也是比较常见的。 构造函数…

《从零开始学习Linux》——开篇

前言 近日笔者新开专栏&#xff0c;《从零开始学习Linux》&#xff0c;Linux水深而且大&#xff0c;学了一圈之后&#xff0c;有懂得有不懂的&#xff0c;一直没有机会整体的全部重新捋一遍&#xff0c;本专栏的目的是&#xff0c;带着大家包括我自己重新学习Linux一遍这些知识…

Taro自定义FromData实现本地路径转换为文件

在用Taro写头像上传功能时&#xff0c;因为需要对获得的图片进行剪切成圆形或方形。使用组件剪切完之后返回的是一个本地图片的相对路径。这个时候我们就需要自己实现将本地路径重新转换为二进制文件。 引入两个js文件 mimeMap.js module.exports {"0.001": &quo…

Java集合类常见面试题

一些常见的Java集合类高频面试题包括&#xff1a; ArrayList和LinkedList的区别是什么&#xff1f;HashMap和HashTable的区别是什么&#xff1f;HashSet和TreeSet的区别是什么&#xff1f;ConcurrentHashMap的实现原理是什么&#xff1f;如何遍历HashMap和HashTable&#xff1…

UDP通讯实现

服务器端&#xff1a; 1.获取套接字 int fd;fdsocket(AF_INET,SOCK_DGRAM,0);if(fd<0){perror("socket");exit(0);} #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); -domain: 指定通信域&…

Spring 事务管理配置方法

Spring中声明式的事务配置方法有两种&#xff0c;一种是注解方式&#xff0c;另一种可能用AOP切片方式来实现。 一、注解方式 在Spring配置文件中加入配置 <!-- DataSource配置 --><bean id"dataSource"class"com.mchange.v2.c3p0.ComboPooledDataSo…

IC后端设计中的shrink系数设置方法

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在一些成熟的工艺节点通过shrink的方式(光照过程中缩小特征尺寸比例)得到了半节点,比如40nm从45nm shrink得到,28nm从32nm shrink得到,由于半节点的性能更优异,成本又低,漏电等不利因素也可以…