当前位置: 首页 > news >正文

Qt事件处理机制2-事件函数的传播

所有继承自QObject的类都有event函数,该函数用来处理自身的事件,函数定义如下:

virtual bool QObject::event(QEvent *e)

Qt帮助文档:
This virtual function receives events to an object and should return true if the event e recognized and processed. The event() function can be reimplemented to customize the behavior of an object. Make sure you call the parent event class implementation for all the events you did not handle.

大致意思:在event函数中,当事件被识别并处理后,如果返回true,表示该event函数执行结束,不再希望执行具体的事件处理函数,例如mousePressEventpaintEvent等;如果返回false,也表示该event函数执行结束,不再希望执行具体的事件处理函数,但事件会向上传递,即传递给父组件,进入父组件的event函数。也可以event函数中调用父类的event函数,交给父类来处理,父类仍旧遵循以上规则。
:当event函数中返回true之前,若已经设置了e->ignore(),仍旧会调用父组件的event函数;只有当event函数返回true,并且e->isAccepted()也为true的时候,才不再调用父组件的event函数。QEvent *e的默认值是true,除非在eventFilter函数中设置为false

下面关于文档里说的返回值,进行演示说明

MyButton.h

#ifndef MYBUTTON_H
#define MYBUTTON_H#include <QPushButton>class MyButton : public QPushButton
{Q_OBJECT
public:MyButton(QWidget *parent = nullptr);~MyButton();protected:bool event(QEvent *e) override;
};#endif // MYBUTTON_H

MyButton.cpp

#include "MyButton.h"
#include <QDebug>
#include <QEvent>MyButton::MyButton(QWidget *parent) : QPushButton(parent){}MyButton::~MyButton(){}bool MyButton::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << event->isAccepted();return true;}return QPushButton::event(e);
}

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();protected:bool event(QEvent *e) override;private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
#include <QEvent>
#include <QMouseEvent>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}bool MainWindow::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << e->isAccepted();}return QMainWindow::event(e);
}

鼠标点击MyButton类按钮,运行结果: 事件向父类传播

// 情形1:直接return false
bool MyButton::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << event->isAccepted();return false;}return QPushButton::event(e);
}// 情形2:e->ignore()后return true
bool MyButton::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << event->isAccepted();e->ignore();return true;}return QPushButton::event(e);
}// 运行结果都如下:
MyButton::event true
MainWindow::event true

鼠标点击MyButton类按钮,运行结果: 事件停止向父类传播

// 情形3:直接return true
bool MyButton::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << event->isAccepted();return true;}return QPushButton::event(e);
}// 情形3:返回父类event函数的处理结果
bool MyButton::event(QEvent *e)
{if (e->type() == QEvent::MouseButtonPress){qDebug() << __FUNCTION__ << event->isAccepted();}return QPushButton::event(e);
}// 运行结果都如下:
MyButton::event true

补充1:QT源码中事件处理过程中调用函数如下:

QApplication::exec()QCoreApplication::exec()QEventLoop::exec(ProcessEventsFlags )QEventLoop::processEvents(ProcessEventsFlags )QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags)QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)bool QETWidget::translateMouseEvent(const MSG &msg)bool QApplicationPrivate::sendMouseEvent(...)inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)bool QApplication::notify(QObject *receiver, QEvent *e)bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)bool QWidget::event(QEvent *event)

补充2:notify函数中处理事件传播
notify函数中处理事件传播的时候,会调用notify_helper函数,当(res && eventAccepted)为真时停止向父类传播,否则w = w->parentWidget(),进而调用父类的notify_helper函数,而notify_helper函数中会调用receiver->event(e)函数。

bool QApplication::notify(QObject *receiver, QEvent *e)
{QWidget* w = static_cast<QWidget *>(receiver);QMouseEvent* mouse = static_cast<QMouseEvent*>(e);QPoint relpos = mouse->pos();...switch (e->type()) {...case QEvent::MouseButtonPress:case QEvent::MouseButtonRelease:case QEvent::MouseButtonDblClick:case QEvent::MouseMove:{...bool eventAccepted = mouse->isAccepted();QPointer<QWidget> pw = w;while (w) {QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(),mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());me.spont = mouse->spontaneous();me.setTimestamp(mouse->timestamp());QGuiApplicationPrivate::setMouseEventFlags(&me, mouse->flags());// throw away any mouse-tracking-only mouse eventsif (!w->hasMouseTracking()&& mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {// but still send them through all application event filters (normally done by notify_helper)d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);res = true;} else {w->setAttribute(Qt::WA_NoMouseReplay, false);res = d->notify_helper(w, w == receiver ? mouse : &me);e->spont = false;}eventAccepted = (w == receiver ? mouse : &me)->isAccepted();if (res && eventAccepted)break;if (w->isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))break;relpos += w->pos();w = w->parentWidget();}...}...
}
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
{// These tracepoints (and the whole function, actually) are very similar// to the ones in QCoreApplicationPrivate::notify_helper; the reason for their// duplication is because tracepoint symbols are not exported by QtCore.// If you adjust the tracepoints here, consider adjusting QCoreApplicationPrivate too.Q_TRACE(QApplication_notify_entry, receiver, e, e->type());bool consumed = false;bool filtered = false;Q_TRACE_EXIT(QApplication_notify_exit, consumed, filtered);// send to all application event filtersif (threadRequiresCoreApplication()&& receiver->d_func()->threadData->thread == mainThread()&& sendThroughApplicationEventFilters(receiver, e)) {filtered = true;return filtered;}if (receiver->isWidgetType()) {QWidget *widget = static_cast<QWidget *>(receiver);#if !defined(QT_NO_CURSOR)// toggle HasMouse widget state on enter and leaveif ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) &&(!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window()))widget->setAttribute(Qt::WA_UnderMouse, true);else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave)widget->setAttribute(Qt::WA_UnderMouse, false);
#endifif (QLayout *layout=widget->d_func()->layout) {layout->widgetEvent(e);}}// send to all receiver event filtersif (sendThroughObjectEventFilters(receiver, e)) {filtered = true;return filtered;}// deliver the eventconsumed = receiver->event(e);QCoreApplicationPrivate::setEventSpontaneous(e, false);return consumed;
}

注: event函数中调用e->ignore()之后,父对象的event函数中e->isAccepted()值仍然为true的原因是每一次调用notify_helper函数时,传递的事件e都是临时的。

QMouseEvent* mouse = static_cast<QMouseEvent*>(e);
...
QMouseEvent me(mouse->type(), relpos, mouse->windowPos(), mouse->globalPos(), mouse->button(), mouse->buttons(), mouse->modifiers(), mouse->source());
...
res = d->notify_helper(w, w == receiver ? mouse : &me);

注: 补充1的内容引自QT QEvent 事件调用的来龙去脉,作者:QtC++ 开发从业者

相关文章:

Qt事件处理机制2-事件函数的传播

所有继承自QObject的类都有event函数&#xff0c;该函数用来处理自身的事件&#xff0c;函数定义如下&#xff1a; virtual bool QObject::event(QEvent *e)&#xff1b;Qt帮助文档&#xff1a; This virtual function receives events to an object and should return true i…...

【PDF.js】PDF文件预览

【PDF.js】PDF文件预览 一、PDF.js二、PDF.js 下载1、下载PDF.js2、在项目中引入3、屏蔽跨域错误 三、项目中使用四、说明五、实现效果 使用PDFJS实现pdf文件的预览&#xff0c;支持预览指定页、关键词搜索、缩略图、页面尺寸调整等等。 一、PDF.js 官方地址 文档地址 二、PD…...

从建表语句带你学习doris_表索引

1、doris建表概述 1.1、doris建表模板 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [DATABASE.]table_name (column_definition1[,column_deinition2,......][,index_definition1,[,index_definition2,]] ) [ENGINE [olap|mysql|broker|hive]] [key_desc] [COMMENT "tabl…...

Linux CentOS 安装 MySQL 服务教程

Linux CentOS 安装 MySQL 服务教程 1. 查看系统和GNU C库(glibc)版本信息 1.1 查询机器 glibc 版本信息 glibc&#xff0c;全名GNU C Library&#xff0c;是大多数Linux发行版中使用的C库&#xff0c;为系统和应用程序提供核心的API接口。在Linux系统中&#xff0c;特别是在…...

MSSQL 命令行操作说明 sql server 2022 命令行下进行配置管理

说明&#xff1a;本文的内容是因为我在导入Access2019的 *.accdb 格式的数据时&#xff0c;总是出错的背景下&#xff0c;不得已搜索和整理了一下&#xff0c;如何用命令行进行sql server 数据库和用户管理的方法&#xff0c;作为从Access2019 直接导出数据到sql server 数据库…...

【系统分析师】系统安全分析与设计

文章目录 1、安全基础技术1.1 密码相关1.1.1对称加密1.1.2非对称加密1.1.3信息摘要1.1.4数字签名1.1.5数字信封 1.2 PKI公钥体系 2、信息系统安全2.1 保障层次2.2 网络安全2.2.1WIFI2.2.2 网络威胁与攻击2.2.3 安全保护等级 2.3计算机病毒与木马2.4安全防范体系 1、安全基础技术…...

ActiveMQ 07 集群配置

Active MQ 07 集群配置 官方文档 http://activemq.apache.org/clustering 主备集群 http://activemq.apache.org/masterslave.html Master Slave TypeRequirementsProsConsShared File System Master SlaveA shared file system such as a SANRun as many slaves as requ…...

Redis(哨兵模式)

什么是哨兵机制 问题: redis 主从复制模式下, 一旦主节点由于故障不能提供服务, 需要人工进行主从切换, 同时大量客户端需要被通知切换到新的主节点上, 对于有一定规模的应用来说, 对于人力的资源消耗会很大.解决: 通过哨兵对主从结构进行监控, 一旦出现主节点挂了的情况, 自动…...

一种基于镜像指示位办法的RingBuffer实现,解决Mirror和2的幂个数限制

简介 在嵌入式开发中&#xff0c;经常有需要用到RingBuffer的概念&#xff0c;在RingBuffer中经常遇到一个Buffer满和Buffer空的判断的问题&#xff0c;一般的做法是留一个单位的buffer不用&#xff0c;这样做最省事&#xff0c;但是当RingBuffer单位是一个结构体时&#xff0…...

【Java开发指南 | 第十一篇】Java运算符

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 算术运算符关系运算符位运算符逻辑运算符赋值运算符条件运算符&#xff08;?:&#xff09;instanceof 运算符Java运算符优先级 Java运算符包括&#xff1a;算术运算符、关系运算符、位运算符、逻辑运算符、赋值…...

【IC前端虚拟项目】验证环境方案思路和文档组织

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 对于mvu的验证环境,从功能角度就可以分析出需要搭建哪些部分,再看一下mvu的周围环境哈: 很明显验证环境必然要包括几个部分: 1.模拟idu发送指令; 2.模拟ram/ddr读写数据; 3.rm模拟mvu的行为; …...

程序设计|C语言教学——C语言基础1:C语言的引入和入门

一、程序的执行 1.定义 解释&#xff1a;借助一个程序&#xff0c;那个程序能够试图理解你的程序&#xff0c;然后按照你的要求执行。下次执行的时候还需要从零开始解释。 编译&#xff1a;借助一个程序&#xff0c;能够像翻译官一样&#xff0c;把你的程序翻译成机器语言&a…...

初学python记录:力扣928. 尽量减少恶意软件的传播 II

题目&#xff1a; 给定一个由 n 个节点组成的网络&#xff0c;用 n x n 个邻接矩阵 graph 表示。在节点网络中&#xff0c;只有当 graph[i][j] 1 时&#xff0c;节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接&#xff0c…...

LlamaIndex 组件 - Storing

文章目录 一、储存概览1、概念2、使用模式3、模块 二、Vector Stores1、简单向量存储2、矢量存储选项和功能支持3、Example Notebooks 三、文件存储1、简单文档存储2、MongoDB 文档存储3、Redis 文档存储4、Firestore 文档存储 四、索引存储1、简单索引存储2、MongoDB 索引存储…...

在Linux系统中设定延迟任务

一、在系统中设定延迟任务要求如下&#xff1a; 要求&#xff1a; 在系统中建立easylee用户&#xff0c;设定其密码为easylee 延迟任务由root用户建立 要求在5小时后备份系统中的用户信息文件到/backup中 确保延迟任务是使用非交互模式建立 确保系统中只有root用户和easylee用户…...

JVM之方法区的详细解析

方法区 方法区&#xff1a;是各个线程共享的内存区域&#xff0c;用于存储已被虚拟机加载的类信息、常量、即时编译器编译后的代码等数据&#xff0c;虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xff0c;但是也叫 Non-Heap&#xff08;非堆&#xff09; 设置方法…...

Go 使用ObjectID

ObjectID介绍 MongoDB中的ObjectId是一种特殊的12字节 BSON 类型数据&#xff0c;用于为主文档提供唯一的标识符&#xff0c;默认情况下作为 _id 字段的默认值出现在每一个MongoDB集合中的文档中。以下是ObjectId的具体组成&#xff1a; 1. 时间戳&#xff08;Timestamp&…...

基于SpringBoot+Vue的疾病防控系统设计与实现(源码+文档+包运行)

一.系统概述 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对疾病防控信息管理的提升&a…...

2024年阿里云4核8G配置云服务器价格低性能高!

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…...

关于ContentProvider这一遍就够了

ContentProvider是什么&#xff1f; ContentProvider是Android四大组件之一&#xff0c;主要用于不同应用程序之间或者同一个应用程序的不同部分之间共享数据。它是Android系统中用于存储和检索数据的抽象层&#xff0c;允许不同的应用程序通过统一的接口访问数据&#xff0c;…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

tauri项目,如何在rust端读取电脑环境变量

如果想在前端通过调用来获取环境变量的值&#xff0c;可以通过标准的依赖&#xff1a; std::env::var(name).ok() 想在前端通过调用来获取&#xff0c;可以写一个command函数&#xff1a; #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

Java高级 |【实验八】springboot 使用Websocket

隶属文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 系列文章&#xff1a;Java高级 | 【实验一】Springboot安装及测试 |最新-CSDN博客 Java高级 | 【实验二】Springboot 控制器类相关注解知识-CSDN博客 Java高级 | 【实验三】Springboot 静…...

Linux 中替换文件中的某个字符串

如果你想在 Linux 中替换文件中的某个字符串&#xff0c;可以使用以下命令&#xff1a; 1. 基本替换&#xff08;sed 命令&#xff09; sed -i s/原字符串/新字符串/g 文件名示例&#xff1a;将 file.txt 中所有的 old_text 替换成 new_text sed -i s/old_text/new_text/g fi…...