QT3学习之进阶理解信号和槽:如何自定义一个类信号,供其它类调用槽函数

 下面是QWidget源码,定义了两个事件

/*!This event handler can be reimplemented in a subclass to receivewidget enter events.An event is sent to the widget when the mouse cursor enters thewidget.\sa leaveEvent(), mouseMoveEvent(), event()
*/void QWidget::enterEvent( QEvent * )
{
}/*!This event handler can be reimplemented in a subclass to receivewidget leave events.A leave event is sent to the widget when the mouse cursor leavesthe widget.\sa enterEvent(), mouseMoveEvent(), event()
*/void QWidget::leaveEvent( QEvent * )
{
}/*!This event handler can be reimplemented in a subclass to receivepaint events.A paint event is a request to repaint all or part of the widget.It can happen as a result of repaint() or update(), or because thewidget was obscured and has now been uncovered, or for many otherreasons.Many widgets can simply repaint their entire surface when askedto, but some slow widgets need to optimize by painting only therequested region: QPaintEvent::region(). This speed optimizationdoes not change the result, as painting is clipped to that regionduring event processing. QListView and QCanvas do this, forexample.Qt also tries to speed up painting by merging multiple paintevents into one. When update() is called several times or thewindow system sends several paint events, Qt merges these eventsinto one event with a larger region (see QRegion::unite()).repaint() does not permit this optimization, so we suggest usingupdate() when possible.When the paint event occurs, the update region has normally beenerased, so that you're painting on the widget's background. Thereare a couple of exceptions and QPaintEvent::erased() tells youwhether the widget has been erased or not.The background can be set using setBackgroundMode(),setPaletteBackgroundColor() or setBackgroundPixmap(). Thedocumentation for setBackgroundMode() elaborates on thebackground; we recommend reading it.\sa event(), repaint(), update(), QPainter, QPixmap, QPaintEvent
*/


 

 

1. 与内置事件处理机制的关联问题

在 Qt 3 里,对于像鼠标进入、移出这类事件,框架本身期望开发者通过重写对应的虚函数来处理,例如重写 QWidget 类中的 enterEvent(QEvent *) 和 leaveEvent(QEvent *) 虚函数。而你定义的 onMouseEnter 和 onMouseLeave 只是普通的成员函数,它们并没有自动与鼠标进入、移出的实际事件触发关联起来。也就是说,当鼠标真正进入或移出按钮这个 QWidget 派生类对象时,Qt 3 的事件处理系统并不知道要去调用你这两个函数,所以无法按预期响应鼠标相关行为并发射信号。

2. 信号与槽连接机制的差异

Qt 3 使用的信号与槽连接语法和方式与后续版本不同,遵循的是宏 SIGNAL 和 SLOT 的语法形式,像这样:

connect(senderObject, SIGNAL(signalName()), receiverObject, SLOT(slotName()));

仅仅定义了 onMouseEnter 和 onMouseLeave 这两个槽函数,但没有在代码中展示出它们是如何通过正确的 connect 语句与对应的能反映鼠标进入、移出的内置信号(例如 QWidget 发出的相关鼠标事件信号)建立连接的。没有这个连接,即使函数逻辑本身没问题,在运行时也不会被触发执行,导致无法响应相应事件。

3. 缺少必要的头文件包含(可能)

虽然从之前你整体代码的展示来看有一些必要的头文件包含了,但就这两个函数所在的代码片段单独看,如果涉及到一些例如信号与槽相关的宏定义或者 QEvent 类型(假设在更完整代码里 enterEvent 和 leaveEvent 等处理中会用到)等使用时,不清楚是否有完整包含对应的头文件。在 Qt 3 中如果缺少必要头文件,编译阶段就可能出现找不到对应定义等错误,导致代码无法通过编译,也就不能正确运行了。

4. 缺少对父类事件处理的调用(可能影响行为)

当重写事件处理相关函数时(虽然你这里目前写法不是标准的重写方式,但假设要改成符合规范的方式),为了保证原有的事件处理逻辑链条完整,通常需要在重写的函数中合适的地方调用父类的对应事件处理函数。比如在重写 enterEvent 或者 leaveEvent 函数时,在完成自定义的信号发射等操作后,调用 QPushButton::enterEvent(event) 或 QPushButton::leaveEvent(event) (取决于具体重写的函数),不然可能会破坏原有的一些默认行为,例如界面更新等操作可能无法正常进行,影响整个按钮在界面中的表现以及与其他部件交互的逻辑一致性。

以下是一种修改为符合 Qt 3 规范的示例代码,来正确处理鼠标进入、移出事件并发射相应信号:

#ifndef CUSTOMSTYLEDBUTTON_H
#define CUSTOMSTYLEDBUTTON_H#include <qpushbutton.h>
#include <qobject.h>
#include <qevent.h>class CustomStyledButton : public QPushButton
{Q_OBJECT
public:CustomStyledButton(QWidget* parent = 0);~CustomStyledButton();signals:void mouseEntered();void mouseLeft();protected:void enterEvent(QEvent *event);  // 重写鼠标进入事件处理函数void leaveEvent(QEvent *event);  // 重写鼠标移出事件处理函数private:bool m_mouseInside;
};#endif // CUSTOMSTYLEDBUTTON_H

源文件(CustomStyledButton.cpp

#include "CustomStyledButton.h"CustomStyledButton::CustomStyledButton(QWidget* parent): QPushButton(parent),m_mouseInside(false)
{
}CustomStyledButton::~CustomStyledButton()
{
}// 重写鼠标进入事件处理函数
void CustomStyledButton::enterEvent(QEvent *event)
{if (!m_mouseInside) {m_mouseInside = true;emit mouseEntered();}QPushButton::enterEvent(event);  // 调用父类的进入事件处理函数,确保原有逻辑延续
}// 重写鼠标移出事件处理函数
void CustomStyledButton::leaveEvent(QEvent *event)
{if (m_mouseInside) {m_mouseInside = false;emit mouseLeft();}QPushButton::leaveEvent(event);  // 调用父类的移出事件处理函数,确保原有逻辑延续
}

在上述代码中:

  • 通过在类中重写 enterEvent 和 leaveEvent 这两个虚函数,使其能够被 Qt 3 的事件处理系统在相应鼠标事件发生时自动调用,符合 Qt 3 处理这类事件的标准流程。
  • 在重写的函数里根据 m_mouseInside 的状态来决定是否发射 mouseEntered 和 mouseLeft 信号,以此实现了想要的在鼠标进入、移出时通知外部的功能。
  • 同时调用了父类对应的事件处理函数,保证了原有事件处理逻辑(例如可能涉及到界面显示相关的默认操作等)能够继续执行,维持了整个按钮行为的完整性和正确性。

你可以根据实际需求进一步扩展这些函数中的逻辑,比如在信号发射后,外部连接这些信号的槽函数里可以进行改变按钮样式等更多与业务相关的操作。

在 Qt 3 中,要调用上述处理鼠标进入和移出事件并发射信号的代码,可以按照以下方式进行操作:

1. 在其他类中连接信号与槽

假设你有一个包含 CustomStyledButton 实例的窗口类(例如继承自 QWidget 或者 QMainWindow 等的类),以下是在这个窗口类的构造函数中连接 CustomStyledButton 的鼠标相关信号到对应的槽函数的示例代码(这里的槽函数是你在窗口类中自定义的用于响应按钮鼠标进入、移出的处理函数):

#include "your_window_header.h"  // 替换为你实际的窗口类头文件
#include "CustomStyledButton.h"YourWindowClass::YourWindowClass(QWidget *parent): QWidget(parent)
{CustomStyledButton *customButton = new CustomStyledButton(this);// 使用Qt 3的信号与槽连接语法进行连接connect(customButton, SIGNAL(mouseEntered()), this, SLOT(onButtonMouseEntered()));connect(customButton, SIGNAL(mouseLeft()), this, SLOT(onButtonMouseLeft()));// 其他界面布局相关操作,比如设置按钮位置、大小等customButton->setGeometry(100, 100, 100, 50);
}

在上述代码中:

  • 首先创建了一个 CustomStyledButton 实例,然后使用 connect 函数按照 Qt 3 的语法格式,将 CustomStyledButton 实例发出的 mouseEntered 信号连接到当前窗口类(YourWindowClass )的 onButtonMouseEntered 槽函数,同理将 mouseLeft 信号连接到 onButtonMouseLeft 槽函数。这里的 onButtonMouseEntered 和 onButtonMouseLeft 是你需要在 YourWindowClass 中定义的成员函数,用于具体处理按钮鼠标进入、移出时想要执行的操作,示例如下:

class YourWindowClass : public QWidget
{Q_OBJECT
public:YourWindowClass(QWidget *parent = 0);
private slots:void onButtonMouseEntered();void onButtonMouseLeft();
};

对应的 .cpp 文件中实现这两个槽函数:

#include "YourWindowClass.h"void YourWindowClass::onButtonMouseEntered()
{// 在这里编写当按钮鼠标进入时想要执行的操作,比如改变按钮的外观CustomStyledButton *button = qobject_cast<CustomStyledButton *>(sender());if (button) {button->setStyleSheet("background-color: yellow;");  // 示例,将按钮背景设为黄色}
}void YourWindowClass::onButtonMouseLeft()
{// 在这里编写当按钮鼠标移出时想要执行的操作,比如恢复按钮原来的外观CustomStyledButton *button = qobject_cast<CustomStyledButton *>(sender());if (button) {button->setStyleSheet("");  // 恢复默认样式,示例做法,具体按实际需求调整}
}

在 onButtonMouseEntered 和 onButtonMouseLeft 函数中:

  • 通过 qobject_cast 尝试将发送信号的对象转换为 CustomStyledButton 类型,这样可以获取到具体触发信号的按钮实例(在有多个同类按钮等复杂场景下很有用),然后就可以针对该按钮进行相应的操作了,比如改变它的样式(这里只是简单示例了通过 setStyleSheet 改变背景颜色来体现按钮外观变化)。

2. 在主函数中使用窗口类及按钮

在 main 函数中创建并显示包含了 CustomStyledButton 的窗口,示例代码如下:

#include <qapplication.h>
#include "YourWindowClass.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);YourWindowClass window;window.show();return app.exec();
}

这样,当运行程序时,鼠标进入 CustomStyledButton 按钮区域时,会触发 mouseEntered 信号,进而调用 YourWindowClass 中定义的 onButtonMouseEntered 槽函数执行相应操作;当鼠标移出按钮区域时,会触发 mouseLeft 信号并调用 onButtonMouseLeft 槽函数来执行对应的操作,实现了对鼠标进入、移出按钮这一行为的响应及相关处理逻辑。

需要注意的是,以上代码只是示例性质,你可以根据实际需求进一步扩展和完善功能,比如添加更多复杂的界面交互逻辑、更丰富的按钮样式改变操作等内容。

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

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

相关文章

GaLore和Q-GaLore:一种记忆高效的预训练和微调策略,用于大型语言模型(LLMs)

GaLore和Q-GaLore&#xff1a;一种记忆高效的预训练和微调策略&#xff0c;用于大型语言模型&#xff08;LLMs&#xff09; GaLore和Q-GaLore的设计背景、工作原理及其优势 设计背景 随着大型语言模型&#xff08;LLMs&#xff09;的发展&#xff0c;模型的规模和复杂性不断…

【网络云计算】2024第51周-每日【2024/12/17】小测-理论-解析

文章目录 1. 计算机网络有哪些分类2. 计算机网络中协议与标准的区别3. 计算机网络拓扑有哪些结构4. 常用的网络设备有哪些&#xff0c;分属于OSI的哪一层5. IEEE802局域网标准有哪些 【网络云计算】2024第51周-每日【2024/12/17】小测-理论-解析 1. 计算机网络有哪些分类 计算…

ActiveMQ 反序列化漏洞CVE-2015-5254复现

文章目录 一、产生原因二、利用条件三、利用过程四、PoC&#xff08;概念验证&#xff09;五、poc环境验证使用find搜索vulhub已安装目录打开activeMQ组件查看配置文件端口启动镜像-文件配置好后对于Docker 镜像下载问题及解决办法设置好镜像源地址&#xff0c;进行重启docker查…

shardingsphere分库分表跨库访问 添加分片规则

shardingsphere分库分表跨库访问 添加分片规则 建立 JDBC 环境 创建表 t_order&#xff1a; CREATE TABLE t_order (tid bigint(20) NOT NULL,tname varchar(255) DEFAULT NULL,goods_id bigint(20) DEFAULT NULL,tstatus varchar(255) DEFAULT NULL,PRIMARY KEY (tid) ) E…

C++ 中,构造函数、拷贝构造函数和移动构造函数区别

在 C 中&#xff0c;构造函数、拷贝构造函数和移动构造函数是类中用于对象初始化的三种不同类型的构造函数。它们的功能和使用场景有所不同&#xff0c;下面详细解释它们之间的区别。 1. 构造函数 (Constructor) 定义&#xff1a; 构造函数是一个特殊的成员函数&#xff0c;用…

MYSQL执行一条update语句,期间发生了什么

客户端先通过连接器建立连接&#xff0c;连接器自会判断用户身份&#xff1b; 因为这是一条 update 语句&#xff0c;所以不需要经过查询缓存&#xff0c;但是表上有更新语句&#xff0c;是会把整个表的查询缓存清空的&#xff0c;所以说查询缓存很鸡肋&#xff0c;在 MySQL 8…

vue3监听横向滚动条的位置;鼠标滚轮滑动控制滚动条滚动;监听滚动条到顶端

1.横向取值scrollLeft 竖向取值scrollTop 2.可以监听到最左最右侧 3.鼠标滚轮滑动控制滚动条滚动 效果 <template><div><div class"scrollable" ref"scrollableRef"><!-- 内容 --><div style"width: 2000px; height: 100…

深入理解MyBatis的Mapper层:让数据访问更高效

目录 1. 什么是MyBatis的Mapper层&#xff1f; 1.1 典型的Mapper层结构 1.2 示例&#xff1a;一个简单的用户管理系统 2. 创建Mapper层 2.1 创建实体类 2.2 创建Mapper接口 2.3 创建Mapper XML文件&#xff08;可选&#xff09; 2.4 配置MyBatis的SQL映射 3. 使用Mapp…

WPF xaml 文件详解

<div id"content_views" class"htmledit_views"><h2><a name"t0"></a>1.总述</h2> 创建好了WPF项目后&#xff0c;最重要的是对 App和MainWindow的理解&#xff0c;在一开始的时候&#xff0c;极容易就直接在Main…

鸿蒙开发-ArkTS 创建自定义组件

在 ArkTS 中创建自定义组件是一个相对简单但功能强大的过程。以下是如何在 ArkTS 中创建和使用自定义组件的详细步骤&#xff1a; 一、定义自定义组件 使用Component注解&#xff1a;为了注册一个组件&#xff0c;使其能够在其他文件中被引用&#xff0c;你需要使用Component…

Golang学习笔记_05——延迟调用

Golang学习笔记_02——函数 Golang学习笔记_03——匿名函数和闭包 Golang学习笔记_04——递归函数 文章目录 延迟调用1. 延迟调用1.1 使用场景1.2 示例 2. panic2.1 使用场景2.2 示例 3. recover3.1 使用场景3.2 示例 源码 延迟调用 在Go语言中&#xff0c;延迟调用&#xff0…

防范TCP攻击:策略与实践

TCP&#xff08;传输控制协议&#xff09;是互联网通信的核心协议之一&#xff0c;它确保了数据在网络上的可靠传输。然而&#xff0c;TCP也容易成为各种网络攻击的目标&#xff0c;如SYN洪水攻击、TCP连接耗尽攻击等。本文将探讨如何通过配置防火墙规则、优化服务器设置以及采…

水表的数字表盘分割数据集labelme格式3023张13类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;3023 标注数量(json文件个数)&#xff1a;3023 标注类别数&#xff1a;13 标注类别名称:["readbox_1","center",&q…

【go语言】reflect包与类型推断

reflect 包的核心概念 Go 中的反射涉及两个核心概念&#xff1a; Type&#xff1a;表示一个类型的结构体&#xff0c;reflect.Type 是类型的描述。Value&#xff1a;表示一个值的结构体&#xff0c;reflect.Value 是一个具体值的包装。 反射让我们能够动态地访问对象的类型和…

跟着AI 学 AI, 开发一个ChatBot, 集成 Json 数据和查询

按照规律&#xff0c;使用AI生成一个架构图 直接上代码&#xff0c;为了方便学习&#xff0c;直接按照如下方式&#xff0c;复制到你的开发环境即可调试&#xff0c;运行代码。做学习参考。 代码注释多次说明这里&#xff0c;不在赘述。 "type": "carousel&qu…

WPF+MVVM案例实战与特效(三十七)- 实现带有水印和圆角的自定义 TextBox 控件

文章目录 1、概述2、案例实现1、基本功能2、代码实现3、控件应用4、案例效果4、总结1、概述 在开发用户界面时,TextBox 是最常见的输入控件之一。为了提升用户体验,我们经常需要为 TextBox 添加一些额外的功能,例如显示提示文本(水印)和设置圆角边框。本文将详细介绍如何…

使用枚举实现单例模式,不会反序列化破坏攻击,不会被反射破坏攻击。(附带枚举单例的简单实现)

原因分析 1.反序列化方法 ① jdk8中的Enum源码中对反序列化方法进行重写&#xff0c;抛出异常。 java.lang.Enum#readObject方法截图如下 ②java.io.ObjectInputStream#readObject 方法中的 readEnum 方法处理了枚举类型的反序列化&#xff0c;从而确保了枚举的单例特性。 …

Linux下的守护程序

启动流程 嵌入式设备下Linux的内核系统启动的流程并不复杂&#xff0c;从最早的父进程init开始&#xff0c;为创建各种服务进程&#xff1a;系统会从 inittab 文件中&#xff0c;读取每一行作为执行命令&#x1f447; # Note: BusyBox init doesnt support runlevels. The r…

2024第十六届蓝桥杯模拟赛(第二期)-Python

# 2024第十六届蓝桥杯模拟赛&#xff08;第二期&#xff09;-Python题解 # 自己改注释# -----------------------1------------------------ # def prime(x): # if x < 2: # return 0 # for i in range(2, int(x ** 0.5) 1): # if x % i 0: # …

MongoDB-副本集

一、什么是 MongoDB 副本集&#xff1f; 1.副本集的定义 MongoDB 的副本集&#xff08;Replica Set&#xff09;是一组 MongoDB 服务器实例&#xff0c;它们存储同一数据集的副本&#xff0c;确保数据的高可用性和可靠性。副本集中的每个节点都有相同的数据副本&#xff0c;但…