Qt界面开发(对象树概念、信号与槽机制)

🌳对象树

在Qt框架中,对象树(Object Tree)是针对QObject类以及其子类的结构化组织方式/每一个QObject实例都可以有一个父对象和多个子对象,形成一种层次化的树状关系。这种设计在Qt中具有多个用途和优势。

概念:

1.父子关系:

每个QObject可以指定一个父对象,当QObject被创建时,可以通过构造函数将其父对象传递进去。

当父对象被销毁时,所有的子对象也会被自动销毁。这种机制帮助管理对象的生命周期,从而防止内存泄露。

2.对象树:

QObject的父对象和子对象的关系可以形成一棵树,树的根节点是最上层的对象,所有的其他对象都是它的后代。

这棵树可以用来组织和分类对象,使得对象之间的关系更加清晰。

用途:

1.内存管理:

通过设置父子关系,可以自动管理对象的内存,当父对象被删除时,所有的子对象也会被删除,程序员无需手动释放内存。

2.信号与槽:

Qt的信号与槽机制依赖于对象的树状结构,信号可以从任何对象发出,而槽则是其他对象中的方法。当对象之间存在父子关系时,信号可以更容易地传播。

3.对象的查找与遍历:

通过QObject::children()方法,可以遍历一个对象地所有子对象,便于管理和操作这些对象。例如开发者可以对特定父对象地所有子对象执行相同的操作。

4.界面组件的组织:

在Qt的图形用户界面(GUI)中,窗口部件通常以父子关系组织。主窗口(父对象)可以拥有多个子窗口部件(如按钮、标签等),这样便于管理和布局。

5.提升可维护性:

清晰的对象树结构可以提高代码的可读性与可维护性。使得理解对象的关系和作用更加直观。


📡信号与槽

前景引入:

信号:signal;槽:slot;信号与槽的本质是两个类成员函数。我们举个例子来理解一下什么是信号与槽:有一天,一个小男孩捡到一个神灯,摩擦了几下,神灯中出现了一个灯神。就这件事,就可以很明了的说明信号与槽机制的概念。

信号的发送者:小男孩;信号:小男孩摩擦的行为产生了一个信号;信号的接收者:神灯;槽:接收摩擦信号神灯的一个槽产生了一个回应,出现神灯的行为。

对应到开发过程中,小男孩就是一个组件,摩擦行为就是组件的一个信号函数,神灯就是另一个组件,出现灯神的行为就是组件对应的槽函数。 小男孩与神灯二者接触产生联系的过程,对应的就是Qt提供的connect()函数将组件,组件信号,组件,组件槽进行关联的一个过程。

现在我们使用开发中的示例来进行说明:我点击一个按钮,窗体关闭。那么这个过程,就包括:按钮组件作为信号的发出者,产生一个点击信号,窗体这个组件作为接收者接收这个点击信号,产生关闭的回应。

简单应用:

基本语法:

connect(part1,&part1.signalfunc,part2,&part2.slotfunc);
//part1:组件一
//&part1.signalfunc:组件一需要简洁对应的信号函数的函数指针//part2:组件二
//&part2.slotfunc:组件二需要链接对应的槽函数的函数指针

函数指针一般情况下是某个类内的成员函数。那么成员函数的函数指针怎么定义呢?我们后面会单独讲解。 

那么,对于上一个示例怎么连接呢?

QPushButton * btn = new QPushButton;
btn->setParent(this);//使按钮依赖于this窗体connect(btn,&QPushButton::Clicked,this,&Widget::Close);

在这个实例中,我们在该窗体(this)下创建了一个QPushButton按钮btn,传入btn的clicked()信号函数的函数指针,然后将这个按钮的点击信号,连接到this窗体的close槽中,也就是close()函数的函数指针。现在只要我点击这个按钮,窗口就可以关闭了。

自定义信号与槽:

我们不止能对Qt提供的组件进行信号与槽链接,我们也能自定义一个类,让自定义类的一些信号与槽与Qt提供的标准组件的信号与槽进行关联,也能使两个自定义类的信号与槽进行关联。我们就以后者进行说明:

现在定义一个teacher类和student类,teacher对象作为信号发出者:下课了信号,student对象作为信号的接收者,槽处理行为是:吃饭去。下面我们开始添加两个类:

弹出需要添加的文件类型:添加自定义类Class

此时你必须输入类名以及可以选择性的选择继承的基类。头文件和源文件都会自动帮你起名字的。

最后汇总:检测无误后就可以完成类的创建了

创建学生myStudent类的过程一样,此处略过。下面是正确创建后的样子:

然后选择信号发出者,自定义信号函数:

1.在signals下定义信号函数,只需要声明,不需要实现。

2.返回值为void

3.信号函数的参数可以自定义,信号可以发生重载。

然后再来到Student类的头文件中:

1.在public或者public slots下写槽函数,需要声明也需要实现

2.返回值为void

3.参数可以自定义,槽函数可以发生重载

4.但关联槽与信号时,参数要对应,信号参数可以多余槽,但槽必须能从信号函数的参数中对应匹配到合适的参数

void signalfunc();
void signalfunc(int a);
void signalfunc(string s,int a);void slotfunc();//可以接收上述任意信号
void slotfunc(int a);//只可以接收第二个信号,不能接收第三个
void slotfunc(string s);//只能接收第三个信号
void slotfunc(string s, int a);//只能几首第三个信号void slotfunc(int a,string s);//不能匹配第三个信号,也不能匹配第二个信号。该槽无法接收以上任意信号

按下F4键转到对应的cpp文件中:

实现类内函数的方法大家都知道,这里介绍一个头文件:<QDebug>

1.qDebug() 函数相当于平常使用的cout,只不过这里我们在Qt自定义的IDE中进行调试查看输出信息,所以需要使用Qt提供的输出方法,如果你习惯之前的方法,可以进行一个宏定义。endl也是Qt::endl,不想写就宏定义以下,使用using展开当然也是可以的。

 

最后我们测试一下链接这两个类的信号与槽,转到widgets.cpp文件中:

在该文件中,我们可以看到我们将两个头文件进行了包含。这是最基础的最不能忘记的操作:包含头文件。此时我们在Widget的构造函数中看到定义了两个对象指针。然后我们使用connect将这两个自定义类的信号与槽链接一下。连接之后我们运行一下:

然后我们发现没有任何输出,为什么呢?因为我们进行链接的时候,需要有触发条件。小男孩虽然可以发出信号,但他不发出信号,神灯怎么出灯神呢?所以我们需要触发一下发送者的信号。现在的问题在于怎么触发,调用一次信号函数?

ok,我们这样就算触发信号然后发送了,对应的,接收者也接收到信号了,做出了响应“下课了,吃东西”。但聪明的小伙伴看到了右边的黄色提示警告信息: 

 这是因为我们的信号函数是只声明,不定义的。调用信号函数当普通函数使用不合法,所以我们需要使用Qt提供的方法来进行触发信号操作:【emit】

此时我们选择将tch和stu定义在widget类内,也就是在widget.h的头文件中:

我们的自定义信号与槽的测试就完成了。总结:

一、自定义信号写法

1.写道signals标签下

2.返回值是void

3.声明实现

4.可发生重载

二、自定义槽函数写法

1.写道public public slots 下,或者是 全局函数lambda表达式

2.返回值是void

3.声明实现

4.可发生重载

三、触发信号的关键字emit

信号与槽的拓展:

1.信号可以链接信号:

即一个A信号可以连接到另一个B信号,那么触发B信号会发生什么,触发A信号就会发生什么,但触发A信号会发生的,B信号触发时不会发生。

2.一个信号可以链接多个槽函数

一个信号可以同时触发多个槽函数。也就是小男孩的摩擦信号,不止能让神灯出现灯神,还能使木头生火,还能给我挠痒痒(嘻嘻)。

3.多个信号可以链接一个槽函数:

一个槽函数可以被多个信号关联。也就是我点击 【x】 按钮可以关闭窗体,也可以点击【退出】按钮关闭窗体。

4.函数与槽重载问题:

函数指针的应用:

当自定义信号与槽发生重载后,需要利用函数指针,明确指出函数地址。

函数地址的类型是什么?

void test(){
}int main(){void(* p_test)();p_test=&test;return 0;
}

p_test就是一个返回值为void,参数列表也为空的一个函数的函数指针,它可以指向test,也可以指向其它同类型的函数,例如:void function();只要返回值类型和参数列表匹配即可。

另一方面,我可以使用typedef将该类型提取出来:

typedef void(* _void_Func_void)();
_void_Func_void  p_test=&test();

其中_void_Func_void是自定义的别名,它的类型就是void(* )(),语法就是将声明指针时,指针的位置改成别名就ok了。

那么类内的成员函数的函数指针是怎样的呢?

class Test{public:void myTestFunc(){}};
int main(){void(Test:: * p_myTest)();p_myTest = &Test::myTestFunc;return 0;
}

唯一的区别就是将作用域明确出来,且限制作用域的位置在*之前。取别名的方式一样。

如果是有参的函数,就将参数类型列表写道后面的括号内就行了,例如:

void(作用域:: * p_func)(char,int);

信号与槽的参数类型,必须一一对应

信号的参数个数可以多余槽函数的参数个数

这两件事我们在讲上文--自定义信号与槽的时候进行了说明,不做赘述,有需要可以往上翻。


感谢大家观看!欲知后事如何?请看下节分晓!

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

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

相关文章

Apache Seata快速入门

前置推荐阅读&#xff1a;Apache Seata 简介-CSDN博客 快速开始 让我们从一个微服务示例开始。 用例​ 用户购买商品的业务逻辑。整个业务逻辑由 3 个微服务提供支持&#xff1a; 仓储服务&#xff1a;对给定的商品扣除仓储数量。订单服务&#xff1a;根据采购需求创建订单…

【Linux】解答:为什么创建目录文件,硬链接数是2;创建普通文件时,硬链接数是1?(超详细图文)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

gitlab配置ssh密钥

1.配置用户信息 git config --global user.name "你的名字" git config --global user.email "你的邮箱" 查看配置是否成功 git config --global --list 2.生成密钥 终端 或 右键文件夹open git bash here 输入命令 ssh-keygen -t rsa -C 随意(生…

接口测试(二)jmeter——实现http请求、察看结果树、请求默认值

一、实现http请求&#xff0c;察看结果树 1. 测试计划 --> 添加 --> 线程(用户) --> 线程组 2. 线程组配置 默认配置 线程数&#xff1a;虚拟用户数&#xff0c;一个虚拟用户占用一个进程或线程。 Ramp-Up 时间&#xff08;秒&#xff09;&#xff1a;全部线程执行完…

使用Jenkins部署项目

部署中的痛点 为什么要用Jenkins&#xff1f;我说下我以前开发的痛点&#xff0c;在一些中小型企业&#xff0c;每次开发一个项目完成后&#xff0c;需要打包部署&#xff0c;可能没有专门的运维人员&#xff0c;只能开发人员去把项目打成一个exe包&#xff0c;可能这个项目已…

Kettle基本使用

目录 一、安装Kelttle 1-1 安装java环境 1-2 Kettle安装 二、Kettle的基本使用 2-1 将txt文本数据转为excel数据 创建txt文件 创建kettle的转换任务 定义转换流程 配置输入文件 连接读取和写入任务 配置excel输出 保存转换任务 执行转换任务 2-2 将txt文件输出到M…

数据库管理-第252期 深入浅出多主多活数据库技术- Cantian存储引擎(二)(20241017)

数据库管理252期 2024-10-17 数据库管理-第252期 深入浅出多主多活数据库技术- Cantian存储引擎&#xff08;二&#xff09;&#xff08;20241017&#xff09;1 部署规划2 服务器基础配置2.1 配置HOSTS2.2 关闭防火墙2.3 关闭SELinux2.4 配置yum源 3 编译服务器配置3.1 安装git…

「Python精品教程」Python快速入门,基础数据结构:数字

​***奕澄羽邦精品教程系列*** 编程环境&#xff1a; 1、Python 3.12.5 2、Visual Studio Code 1.92.1 在现实世界中&#xff0c;我们经常要面对各式各样的数字&#xff0c;通过简单或者复杂的数学运算&#xff0c;来帮助我们计算出想要的结果。程序开发过程中&#xff0c;数字…

自动化测试工具在API测试中的优势是什么?

在设计API接口时&#xff0c;确保数据获取的效率和准确性是至关重要的。以下是一些最佳实践和代码示例&#xff0c;帮助你提高API的数据获取效率和准确性。 1. 使用高效的数据访问模式 选择合适的数据库访问模式对于提高数据获取效率至关重要。例如&#xff0c;使用索引可以显…

【启明智显分享】ZX7981PM WIFI6 5G-CPE:2.5G WAN口,2.4G/5G双频段自动调速

昨天&#xff0c;我们向大家展现了ZX7981PG WIFI6 5G-CPE&#xff0c;它强大的性能也引起了一波关注&#xff0c;与此同时&#xff0c;我们了解到部分用户对更高容量与更高速网口的需求。没关系&#xff01;启明智显早就预料到了&#xff01;ZX7981PM满足你的需求&#xff01; …

Vue3 集成Monaco Editor编辑器

Vue3 集成Monaco Editor编辑器 1. 安装依赖2. 使用3. 效果 Monaco Editor &#xff08;官方链接 https://microsoft.github.io/monaco-editor/&#xff09;是一个由微软开发的功能强大的在线代码编辑器&#xff0c;被广泛应用于各种 Web 开发场景中。以下是对 Monaco Editor 的…

HTML5教程(三)- 常用标签

1 文本标签-h 标题标签&#xff08;head&#xff09;&#xff1a; 自带加粗效果&#xff0c;从h1到h6字体大小逐级递减一个标题独占一行 语法 <h1>一级标题</h1><h2>二级标题</h2><h3>三级标题</h3><h4>四级标题</h4><h5…

关于md5强比较和弱比较绕过的实验

在ctf比赛题中我们的md5强弱比较的绕过题型很多&#xff0c;大部分都是结合了PHP来进行一个考核。这一篇文章我将讲解一下最基础的绕过知识。 MD5弱比较 比较的步骤 在进行弱比较时&#xff0c;PHP会按照以下步骤执行&#xff1a; 确定数据类型&#xff1a;检查参与比较的两…

jmeter响应断言放进csv文件遇到的问题

用Jmeter的json 断言去测试http请求响应结果&#xff0c;发现遇到中文时出现乱码&#xff0c;导致无法正常进行响应断言&#xff0c;很影响工作。于是&#xff0c;察看了其他测试人员的解决方案&#xff0c;发现是jmeter本身对编码格式的设置导致了这一问题。解决方案是在jmete…

【文化课学习笔记】【化学】选必三:同分异构体的书写

【化学】选必三&#xff1a;同分异构体的书写 如果你是从 B 站一化儿笔记区来的&#xff0c;请先阅读我在第一篇有机化学笔记中的「读前须知」(点开头的黑色小三角展开)&#xff1a;链接 链状烃的取代和插空法 取代法 一取代物 甲烷、乙烷、丙烷、丁烷的种类 甲烷&#xff1a;只…

游戏逆向基础-找释放技能CALL

思路&#xff1a;通过send断点然后对send的data参数下写入断点找到游戏里面的技能或者攻击call 进入游戏先选好一个怪物&#xff08;之所以要先选好是因为选怪也会断&#xff0c;如果直接左键打怪的话就会断几次&#xff09; 断下来后对参数下硬件写入断点 硬件断点断下来后先…

如何用pyhton修改1000+图片的名字?

import os oldpath input("请输入文件路径&#xff08;在windows中复制那个图片文件夹的路径就可以):") #注意window系统中的路径用这个‘\分割&#xff0c;但是编程语言中一般都是正斜杠也就是’/‘ #这里写一个代码&#xff0c;将 \ > / path "" fo…

基于SpringBoot+Vue+uniapp的海产品加工销售一体化管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的视频演示 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

基于FPGA的DDS信号发生器(图文并茂+深度原理解析)

篇幅有限,本文详细源文件已打包 至个人主页资源,需要自取...... 前言 DDS(直接数字合成)技术是先进的频率合成手段,在数字信号处理与硬件实现领域作用关键。它因低成本、低功耗、高分辨率以及快速转换时间等优点备受认可。 本文着重探究基于 FPGA 的简易 DDS 信号发生器设…

交叉熵损失 在PyTorch 中的计算过程

其实就是根据 真实值的结果&#xff0c;当成索引去取的值 import torch import torch.nn as nnaaaa torch.tensor([[2.0,1.0,3.0],[2.0,4.0,2.0]])l1 nn.LogSoftmax(dim-1) result l1(aaaa) print(result) import torch import torch.nn as nn# 定义交叉熵损失函数 criterio…