qt5入门-事件

参考:
Qt 事件(event)_w3cschool
https://www.w3cschool.cn/learnroadqt/xvme1j4c.html

本地环境:
win10专业版,64位


事件的概念

将事件抽象为一个对象,当用户发起一个行为,就把对应的事件加入事件队列,对于系统来说,每次只要处理事件队列里未处理的事件就可以了;如果没用事件,程序就阻塞,不执行任何代码。

必要时,Qt的事件也可以不进入事件队列,直接处理。

与信号的区别

  • 信号一旦发出,对应的槽函数一定会被执行,但是事件可以使用事件过滤器进行过滤。
  • 如果使用组件,那么要关心信号槽;如果自定义组件,那么要关心事件。(比如如果自定义一个QPushButton,那么需要重写它的鼠标点击事件和键盘处理时间,并在恰当的时候发出clicked()信号)

如果要使用事件,只要让类继承QWidget类及其子类(里面定义了很多protected virtual函数),然后再重写事件回调函数即可。

简单实例:自定义一个Label,重写鼠标移动、按压和释放事件

初始状态:
在这里插入图片描述
在label内移动:
在这里插入图片描述
鼠标按压:
在这里插入图片描述
鼠标释放:
在这里插入图片描述
代码:

// eventlabel.h
#ifndef EVENTLABEL_H
#define EVENTLABEL_H#include <QLabel>class QLabel;class EventLabel : public QLabel {
protected:void mouseMoveEvent(QMouseEvent *event);void mousePressEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);
};#endif // EVENTLABEL_H// eventlabel.cpp
#include <QWidget>
#include <QMouseEvent>#include "eventlabel.h"void EventLabel::mouseMoveEvent(QMouseEvent *event) {this->setText(QString("<center><h1>Move: (%1, %2)</h1></center>").arg(QString::number(event->x()),QString::number(event->y())));
}void EventLabel::mousePressEvent(QMouseEvent *event) {this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>").arg(QString::number(event->x()),QString::number(event->y())));
}void EventLabel::mouseReleaseEvent(QMouseEvent *event) {// 支持用c格式化字符串的方式写QStringQString msg;msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>",event->x(), event->y());this->setText(msg);
}// main.cpp
#include <QApplication>
#include "eventlabel.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);EventLabel *label = new EventLabel;label->setWindowTitle("DIY Label");label->resize(400, 200);// width, heightlabel->show();return a.exec();
}

事件的接收与忽略

Qt的事件对象都有一个accept()和一个ignore()。对于一个事件,如果子类没有处理这个事件的函数或者忽略了,那么会向上传递事件给父类;否则会接收事件,不再传递。在事件处理函数中可以用isAccepted()查询接收状态。

不过accept()和ignore()是很少用的,如果希望忽略一个事件,只要调用父类的响应函数即可。(如果不传给父类,直接忽略,可能应该执行的操作没有执行,会有危险)。用到它们的情况,例如在窗口关闭时需要询问是否要关闭:
在这里插入图片描述
点击Yes之后才能正常关闭。

// eventlabel.h
protected:void closeEvent(QCloseEvent *event);
private:bool continueToClose();// eventlabel.cpp
#include <QMessageBox>
...
void EventLabel::closeEvent(QCloseEvent *event){if(continueToClose()) {event->accept();}else {event->ignore();}
}bool EventLabel::continueToClose() {if(QMessageBox::question(this, "Quit", "Are you sure?",QMessageBox::Yes | QMessageBox::No,QMessageBox::No) == QMessageBox::Yes){return true;}else {return false;}
}

event()函数

event()是QObject的,它不是直接处理事件的,而是分发给不同的事件处理器(event handler)。如果希望在事件分发之前做一些操作,比如区分一些事件,某些事件在处理之前需要做一些处理。下面的例子是,当在窗口中,按下tab键时,做一些处理,那么应该继承QWidget,然后重写它的event()函数。同时,如果需要自定义事件,同样也要重写event()。

event()函数的返回值是bool型,返回true表示被传入的事件已经被识别并且得到了处理,此时QApplication会认为这个事件已经处理了,然后继续处理事件队列的下一个事件;返回false表示未被处理,QApplication会尝试寻找这个事件的下一个处理函数。

需要注意的是,前面提到的accept()和ignore()是不同事件处理器之间的沟通event()的返回值是通知QApplication的notify()函数是否处理下一个事件。

效果:当按下tab键后,会弹出about提示框。
在这里插入图片描述

// eventlabel.h
protected:bool event(QEvent *event);// eventlabel.cpp
bool EventLabel::event(QEvent *event) {if(event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);if (keyEvent->key() == Qt::Key_Tab) {// 处理QMessageBox::about(this, "", "press Tab");return true;}}return QWidget::event(event);
}

事件过滤器

事件过滤器的作用是筛选哪些事件需要被响应,就是判断哪些事件需要调用event(),进行识别和分发。此时需要重写eventFilter()函数,在有事件过滤器的情况下,这个函数会被优先调用,然后才处理事件。

这个函数的返回值也是bool,返回true表示停止响应。

比如为EventLabel安装一个eventFilter,希望它在面对键盘事件的时候,先发出一条提示信息。

在这里插入图片描述

// eventlabel.h
public:EventLabel();
protected:bool eventFilter(QObject *obj, QEvent *event);// eventlabel.cpp
EventLabel::EventLabel() {// 安装事件过滤器this->installEventFilter(this);
}bool EventLabel::eventFilter(QObject *obj, QEvent *event) {if(obj == this) {if(event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);//qDebug() << "you press: " << keyEvent->key();QMessageBox::about(this, "", QString("%1").arg(keyEvent->key()));return true;} else {return false;}} else {// pass to parentreturn QLabel::eventFilter(obj, event);}
}

这是安装在Label上的。如果假设有个主窗口MainWindow,MainWindow有个组件textEdit(一个QObject对象),假设不希望让textEdit处理键盘事件,那么需要:

  • 在MainWindow上实现eventFilter(),需要判断obj == textEdit,如果是的话,再判断是不是KeyPress,如果是的话返回true,这样不会被父级的evenFilter处理
  • 执行textEdit.installEventFilter(MainWindow),表示如果有事件发送到textEdit,那么先调用MainWindow->eventFilter(),然后才调用textEdit.event()

注意:

  • 事件过滤器也可以安装在QApplication上,这样可以过滤所有事件,但是也会降低事件分发的效率。
  • 如果一个组件安装了多个过滤器,那么最后一个安装的会先调用,类似stack。
  • 如果在事件过滤器中delete了某个接收组件,一定要将返回值设为true,不然Qt仍然会分发给这个组件,但实际是找不到的,那么程序会崩溃
  • 事件过滤器和被安装的组件必须在同一线程,否则过滤器不起作用;如果安装之后,两个组件到了不同的线程,那么只有当二者重回到同一线程才气笑
  • 事件的调用最终都会调用QCoreApplication.notify()。因此Qt的事件处理,控制权由低到高依次是:重定义事件处理函数,重定义event()函数,为单个组件安装事件过滤器,为QApplication安装事件过滤器,重定义QCoreApplication.notify()

自定义事件

自定义事件需要继承QEvent,同时需要提供一个QEvent::TYPE类型(enum)的参数,作为自定义事件的类型值。Qt保留了0-999的值,所以TYPE要大于999,同时需要在QEvent::User和QEvent::MaxUser之间(1000-65535)。由于很难记住这个黍子,所以使用一个函数:

static int QEvent::registerEventType( int hint = -1 );

这个函数接受一个int,如果合法,直接返回,如果不合法,返回一个系统分配的合法值。这个函数是线程安全的,不必添加另外的同步操作。

发送事件有两种方式:(自定义的事件也可以)

  1. send
    事件被QCoreApplication的notify()函数直接发给receiver对象,返回值是事件处理函数的返回值,使用这个函数必须在栈上创建对象
    QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
    QApplication::sendEvent(mainWindow, &event);
    
  2. post
    事件被追加到事件列表的最后,等待处理。线程安全,要在堆上创建对象。
    QApplication::postEvent(object, new MyEvent(QEvent::registerEvenType(2048)));
    
    这个对象不用手动delete,是Qt自动的。postEvent()还有一个带优先级参数的版本。通过调用sendPostedEvent()可以让已提交的事件立即得到处理。

处理自定义事件也有两种方式:

  1. 重写void customEvent(QEvent *event),类似重写event()
  2. 直接重写event
    bool CustomWidget::event(QEvent *event) {if (event->type() == CustomEventType) {CustomeEvent *myEvent = static_cast<CustomeEvent *>(event);// processingreturn true;}return QWidget::event(event);
    }
    

这一块等用到了再补实例。暂时只作理解。

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

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

相关文章

云计算、Docker、K8S问题

1 云计算 云计算作为一种新兴技术&#xff0c;已经在现代社会中得到了广泛应用。它以其高效、灵活和可扩展特性&#xff0c;成为了许多企业和组织在数据处理和存储方面的首选方案。 1.1 什么是云计算&#xff1f;它有哪些特点&#xff1f; 云计算是一种通过网络提供计算资源…

大型软件编程实例分享,诊所门诊处方笺管理系统多台电脑同时使用的软件教程

大型软件编程实例分享&#xff0c;诊所门诊处方笺管理系统多台电脑同时使用的软件教程 一、前言 以下教程以 佳易王诊所门诊电子处方管理系统V17.2 为例说明 软件资源可以点击最下方官网卡片了解详情 软件左侧为导航栏 1、系统参数设置&#xff1a;可以设置打印等参数 2、…

【数据分享】1929-2023年全球站点的逐年降雪深度数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 之前我们分享过1929-2023年全球气象站点的逐年平均气温数据、逐年最高气温数据…

Debian系统显示中文

开发板上的debian默认不显示中文。 安装字体 sudo apt install fonts-wqy-zenhei 安装locals sudo apt install locales &#xff08;无必要&#xff09;设置/etc/locale.gen、设置/etc/locale.conf 运行dpkg-reconfigure locales dpkg-reconfigure locales 可以选择UT…

Sqli靶场23-->30

不知不觉鸽了几天了&#xff0c;没办法去旅游摸鱼是这样的了&#xff0c;抓紧时间来小更一下 23.过滤注释符号 先手工注入一下&#xff0c;就能发现两个单引号不报错&#xff0c;但是一旦上到注释符号的话就会报错&#xff0c;可以猜测出是对注释符号进行了过滤&#xff0c;我…

【Crypto | CTF】BUUCTF 萌萌哒的八戒

天命&#xff1a;这年头连猪都有密码&#xff0c;真是奇葩&#xff0c;怪不得我一点头绪都没有 拿到软件&#xff0c;发现是.zip的压缩包&#xff0c;打不开&#xff0c;改成7z后缀名&#xff0c;打开了 发现是一张图片 也只有下面这行东西是感觉是密码了&#xff0c;又不可能…

前端面试题——Vue的双向绑定

前言 双向绑定机制是Vue中最重要的机制之一&#xff0c;甚至可以说是Vue框架的根基&#xff0c;它将数据与视图模板相分离&#xff0c;使得数据处理和页面渲染更为高效&#xff0c;同时它也是前端面试题中的常客&#xff0c;接下来让我们来了解什么是双向绑定以及其实现原理。…

eslint报错文档大量红色报错符号 不自动修正

确保eslint在工作 控制台大量报错信息 确保setting.json 开了保存的时候自动格式化代码 这个时候保存的时候代码可以自动被格式化 但是 文档中和控制台中仍然有大量的报错 信息 此时此刻说明 格式化文档的文件不是按照eslint 格式化的 可以网上找找现成可用的setting.json抄…

一站式SpringBoot学习平台:让编程变得轻松有趣!

介绍&#xff1a;Spring Boot是一个开源的Java框架&#xff0c;旨在简化Spring应用程序的开发和部署过程。 Spring Boot由Pivotal团队设计并推出&#xff0c;它的核心优势在于极大地简化了传统Spring应用的初始搭建和开发流程。具体来说&#xff0c;Spring Boot的主要特点包括&…

Bard 最新更新:全球开放访问Gemini Pro并生成图片

深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领域的领跑者。点击订阅&#xff0c;与未来同行&#xff01; 订阅&#xff1a;https://rengongzhineng.io/ 。 今…

【讲座分享】| 复旦大学张奇教授——《自然语言发表论文如何打怪升级?NLP顶会论文发表》

文章目录 1 基础关1.1 基础书籍1.2 提高书籍1.3 课程链接1.4 编程实战 2 阅读关2.1 分层过滤2.2 集团作战&#xff0c;信息获取2.3 论文如何泛读 3 动机 方向关3.1 快速发论文3.2 好的研究 4 写作关4.1 论文写作流程4.2 从读者角度出发4.3 每一部分怎么写4.3.1 Abstract摘要4.3…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(八)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十八章&#xff1a;强化学习 强化学习&#xff08;RL&#xff09;是当今最激动人心的机器学习领域之一&#xff0c;也是最古老…

跟着pink老师前端入门教程-day18

3、CSS3 3D转换 生活中的环境是3D的&#xff0c;照片就是3D物体在2D平面呈现的例子 特点&#xff1a;近大远小&#xff0c;物体后面遮挡不可见 3.1 三维坐标系 三维坐标系其实就是指立体空间&#xff0c;立体空间是由3个轴共同组成的 x轴&#xff1a;水平向右 注意&#x…

SpringBoot 使用定时任务(SpringTask)

Spring3.0以后自带的task&#xff0c;可以将它看成一个轻量级的Quartz&#xff0c;而且使用起来比Quartz简单许多。 使用步骤&#xff1a; 1.导入坐标 在spring-boot-starter-web坐标中&#xff0c;就包含了SpringTask&#xff0c;所以一般的Web项目都包含了。 <depende…

基于动作合成视频、线免费使用不需要注册,支持多种视频任务:图像生成视频、文本生成视频、视频修改、视频风格化、用Transformer构建世界模型

基于动作合成视频、线免费使用不需要注册&#xff0c;支持多种视频任务&#xff1a;图像生成视频、文本生成视频、视频修改、视频风格化、用Transformer构建世界模型。 WorldDreamer无缝逐帧AI模型: 基于Transformer生成高质量电影级别视频的通用世界模型"。从20亿数据中…

问题:胚珠裸露于心皮上,无真正的果实的植物为() #经验分享#媒体

问题&#xff1a;胚珠裸露于心皮上&#xff0c;无真正的果实的植物为&#xff08;&#xff09; A.双子叶植物 B.被子植物 C.单子叶植物 D.裸子植物 参考答案如图所示

【节选】Go语言的100个错误使用场景|数据类型

Data types &#x1f31f; 章节概述&#xff1a; 基本类型涉及的常见错误 掌握 slice 和 map 的基本概念&#xff0c;避免使用时产生 bug 值的比较 低效的切片初始化&#xff08;#21&#xff09; 实现一个 conver 方法&#xff0c;将一个切片 Foo 转换成另一个类型的切片 Ba…

基于若依的ruoyi-nbcio流程管理系统自定义业务回写状态的一种新方法(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

【MATLAB源码-第136期】基于matlab的变色龙群优化算法CSA)无人机三维路径规划,输出做短路径图和适应度曲线

操作环境&#xff1a; MATLAB 2022a 1、算法描述 变色龙群优化算法&#xff08;Chameleon Swarm Algorithm&#xff0c;CSA&#xff09;是一种新颖的群体智能优化算法&#xff0c;受到自然界中变色龙捕食和社交行为的启发。变色龙以其独特的适应能力而著称&#xff0c;能够根…

前缀和与差分

前缀和 S [ i ] Σ i j 1 A [ j ] S [ i − 1 ] A [ i ] \text{S}\left[ \text{i} \right] \underset{\text{j}1}{\overset{\text{i}}{\Sigma}}\text{A}\left[ \text{j} \right] \text{S}\left[ \text{i}-1 \right] \text{A}\left[ \text{i} \right] S[i]j1Σi​A[j]S[i−1…