Qt初识简单使用Qt

使用C++代码实现hello world

之前介绍过用图形化界面的方式创建hello world,这里我们使用C++代码的方式再来实现一次hello world。

如上,首先要先包含一个头文件。

在QT这里,每一个类都有一个对应的同名头文件。比如这里我就包含了 <QLabel>

不过,在调用 setText函数的时候

发现这里的参数是一个QString类型,这是什么呢?
这其实是一个历史问题,因为QT是在1991年推出的,那时的C++对字符串类型的定义比较混乱,C++自身的string类型还不是很好用,于是QT就自己造了一个轮子,也就是QString类型,后来C++标准定义的string类型发布了,但是QT也并没有把原来设计的类型删掉,而是保留了下来。

 

但是我们在这里调用的时候,直接传入了一个 "hello world",这是因为C风格的字符串会隐式转化为QString。

关于内存泄漏的问题 

 

还是这个代码,我们发现,我们new了一个QLabel对象后,并没有调用delete来进行释放,这是否会造成内存泄漏呢?
这里是不会造成内存泄漏的,因为在QT中有一个对象树的概念,QLabel继承自它的父类Widget,在我们构造QLabel对象的时候,就把this指针传入了过去,那么也就是将 QLabel对象挂到这个对象树中了。

使用对象树的目的,就是为了能够在合适的时机(比如窗口的关闭/销毁),把这些对象统一进行释放。统一释放这种事情还是挺不错的,如果某一个窗口内有对象提前释放了,这不就是bug了吗

我们这里是通过new的方式创建 QLabel对象的,也就是在堆上创建的,我们也可以在栈上创建,在栈上创建编译器不会报错,但是不建议,因为这样就会导致对象提前被释放了。

比如我们将刚刚实现hello world改为栈上生成:

发现这一次并没有hello world,说明对象被提前释放掉了。

我们知道内存泄漏是一件很可怕的事情,因为不容易被察觉,并且暴露问题的周期不确定,可能是几分钟,几小时,甚至几天。那么,我们将对象挂到对象树中,我们没有手动调用delete,这个对象真的被释放了吗?

为了进行一个验证,我们可以手动创建一个类,让它继承 QLabel,我们手动实现一下析构函数,来进行一个打印的方式进行验证。

先在头文件那里选择创建C++类

 这里我们要选择继承QLabel

点击创建以后,就会帮我们生成对应的.h和.cpp文件

头文件中:

注意,我们要想把对象挂到QT的对象树中,在构造函数中记得传入父类的指针 

Qt中通过继承内置自Qt内置的类,就可以达到对控件进行扩展的效果。 

在头文件中写完声明后,有一个技巧:

 用alt + enter(回车)的方式,自动在对应的.cpp文件中添加函数定义

 在cpp文件中

最后在widget.cpp中调用,记得包含头文件

运行程序

 发现hello world打印出来了,但是因为我们还没关闭窗口,所以MyLabel还没有销毁,当我们关闭窗口后

发现打印了这个,虽然有一些乱码,但是我们能认出这就是我们析构函数打印出来的内容。

关于乱码问题 

有这么一个问题:一个汉字占用多少字节?

如果我们直接回答,那么百分百就是错了,因为现在表示汉字的字符集主要有两种,一种是GBK:也就是Windows下对简体中文用的字符集,另一种是utf-8,在Linux下默认用的就是这种。

然后GBK下一个汉字是2字节,而utf-8下一个汉字一般是3字节。

所有出现乱码问题的原因只有一个:那就是编码方式不匹配。

如果要解决这个乱码问题,我们可以使用qDebug()函数来打印。

比如

 Qt中提供了一个qDebug工具,可以帮我们打印日志,并处理字符编码,还有不需要换行。

qDebug是一个宏,封装了QDebug对象。

并且如果我们使用qDebug,可以很方便的通过编译开关,来进行一键式关闭和打开。

因为我们打印日志主要是给程序员看的,当我们将程序发布上线给用户使用后,当然不应该给用户看到日志信息。

关于为什么不用VS 或者 gdb这样的调试工具来调试,这是因为调试器在很多情况下是有局限性的,比如一个bug出现的概率是1%,这时想要通过调试器来调试就会非常困难和麻烦。

用按钮实现一个hello world

第一种方法:我们同样可以使用图形化界面的方式来实现

 

这是一个按钮,但是没有进行任何处理的话,我们点击这个按钮是没有反应的。

这里就简单说下Qt信号槽机制

这里的本质就是给按钮的点击操作,关联一个处理函数。

当用户点击的时候,就会调用这个处理函数。

这里的设置处理函数的接口就是 connect

这里的connect跟网络套接字那里没有任何关系。

来看一下我这里的调用方式

这里我们发现,我们是用了一个 ui->pushButton。并且显然这个pushButton就是我们的按钮对象

为了做区分,我又用代码的方式创建了一个QLabel
 

运行结果:

可以看到是没问题的,现在的情况就是 这个按钮是我用图形化界面创建的,这个QLabel是我用代码的方式创建的。

接着在设计图形化界面这里:
 我们发现用代码生成的不会显示在这里,并且注意右边,在QPushButton下有一个对象,名字就是pushButton,这个对象其实就是由我们的ui自动帮我们创建的,并且这个对象的名字也是可以由我们进行修改的。我们怎么看到ui的代码呢?

我们先点击在Explorer中显示:
 在build中找到

打开后

 我们发现,这里就会自动帮我们创建一个QPushButton的对象,对象名正是pushButton,它就是ui_Widget的类成员。

所以到这里我们就搞清楚了,为什么通过图形化界面创建的,要通过ui->这种方式使用了。

这下我们也就能理解,在Widget中的这个ui是干啥的了。 

关于connect参数的解释:

 这个handleClick当然也是我们自己实现的:
那么步骤就是:先在Widget.h中进行声明,然后再对应的.cpp中实现:

 

这里我们实现的功能是:如果这个按钮的名字是 hello world hzj,那么就按钮设置为 hello world qt,否则就又设置成 hello world hzj。

这里就是用图形化界面的方式用按钮实现一个hello world,那么用代码的方式如下:
 这里记得也要将这个_myButton作为Widget的成员变量声明一下

对两种实现方式的总结:
 在实际开发中,这两种方式都会用到,都很重要。

使用图形化界面的场景:当界面内容固定,此时就会以图形化界面的方式来构造界面。

使用代码的场景:当程序界面需要经常动态变化时,此时就会用代码的方式构造界面。

给变量/函数/文件/类命名的规范

在C/C++中,一般使用蛇形命名法:
 而在其它的语言中,几乎都使用驼峰命名法,包括Qt这里也是:

项目文件的解析

关于.pro文件 

⼯程新建好之后,在⼯程⽬录列表中有⼀个后缀为 ".pro" 的⽂件, ".pro" ⽂件就是⼯程⽂件 (project) ,它是 qmake ⾃动⽣成的⽤于⽣产 makefile 的配置⽂件。如图所⽰:

 

双击进⼊该⽂件,该⽂件的核⼼内容如下:
QT += core gui // Qt 包含的模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //⼤于 Qt4 版本才包含 widget 模块
TARGET = QtFirst //应⽤程序名⽣成的 .exe 程序名称
TEMPLATE = app //模板类型,应⽤程序模板
SOURCES += main.cpp\ //源⽂件
widget.cpp //源⽂件
HEADERS += widget.h //头⽂件

widget.h ⽂件解析 

在Qt中,如果要使⽤信号与槽(signal 和 slot)的机制 就必须加⼊ Q_OBJECT 宏;
Ui::Widget *ui; 这个指针是⽤前⾯声明的 namespace Ui ⾥的 Widget 类定义的,所以指针 ui 是指向可视化设计的界⾯,后⾯要访问界⾯上的组件,都需要通过这个指针 ui 去访问。

 main.cpp ⽂件解析 

QApplication 为应⽤程序类;QApplication a;(a为应⽤程序对象,有且仅有⼀个。)
⚫ QApplication 管理图形⽤⼾界⾯应⽤程序的控制流和主要设置。
⚫ QApplication 是 Qt 的整个后台管理的命脉。它包含主事件循环,在其中来⾃窗⼝系统和其它
资源的所有事件处理和调度。它也处理应⽤程序的初始化和结束,并且提供对话管理。

⚫ 对于任何⼀个使⽤ Qt 的图形⽤⼾界⾯应⽤程序,都正好存在⼀个 QApplication 对象,⽽不论
这个应⽤程序在同⼀时间内是不是有 0、1、2 或更多个窗⼝。

myWidget w; //实例化窗⼝对象
w.show(); //调⽤show函数显⽰窗⼝
  a.exec() :程序进⼊消息循环,等待对⽤⼾输⼊进⾏响应。这⾥ main()把控制权转交给Qt,Qt 完
成事件处理⼯作,当应⽤程序退出的时候 exec() 的值就会返回。在 exec() 中,Qt 接受并处理⽤⼾
和系统的事件并且把它们传递给适当的窗⼝部件。

Qt Creator中的快捷键 

注释:ctrl + /
运⾏:ctrl + R
编译:ctrl + B
字体缩放:ctrl + ⿏标滑轮
查找:ctrl + F
整⾏移动:ctrl + shift + ⬆/⬇
帮助⽂档:F1
⾃动对⻬:ctrl + i;
同名之间的 .h 和 .cpp 的切换:F4
⽣成函数声明的对应定义: alt + enter

使用帮助文档 

如果我们要查询某一个函数或者类,可以点击一下这个函数,然后按f1

右边就会给我们将文档展示出来

我们还可以点击左边的帮助按钮:

不过实际开发中,还是用到什么,用f1查比较多。 

认识对象模型(对象树) 

在 Qt 中创建很多对象的时候会提供⼀个 Parent 对象指针,下⾯来解释这个 parent 到底是⼲什么的。 

QObject 是以对象树的形式组织起来的。 

当创建⼀个 QObject 对象时,会看到 QObject 的构造函数接收⼀个 QObject 指针作为参数,这
个参数就是 parent,也就是⽗对象指针。
这相当于,在创建 QObject 对象时,可以提供⼀个其⽗对象,我们创建的这个 QObject 对象
会⾃动添加到其⽗对象的 children() 列表。
当⽗对象析构的时候,这个列表中的所有对象也会被析构。(注意,这⾥的⽗对象并不是继承
意义上的⽗类!)
这种机制在 GUI 程序设计中相当有⽤。例如,⼀个按钮有⼀个 QShortcut(快捷键)对象作为其
⼦对象。当删除按钮的时候,这个快捷键理应被删除。这是合理的。

QWidget 是能够在屏幕上显⽰的⼀切组件的⽗类。 

QWidget 继承⾃ QObject ,因此也继承了这种对象树关系。⼀个孩⼦⾃动地成为⽗组件的⼀
个⼦组件。因此,它会显⽰在⽗组件的坐标系统中,被⽗组件的边界剪裁。例如,当⽤⼾关闭
⼀个对话框的时候,应⽤程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该
⼀起被删除。事实就是如此,因为这些都是对话框的⼦组件。
当然,我们也可以⾃⼰删除⼦对象,它们会⾃动从其⽗对象列表中删除 ⽐如,当我们删除了
⼀个⼯具栏时,其所在的主窗⼝会⾃动将该⼯具栏从其⼦对象列表中删除,并且⾃动调整屏幕
显⽰。

Qt 引⼊对象树的概念,在⼀定程度上解决了内存问题。 

当⼀个 QObject 对象在堆上创建的时候,Qt 会同时为其创建⼀个对象树。不过,对象树中对象的
顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
任何对象树中的 QObject 对象 delete 的时候,如果这个对象有 parent,则⾃动将其从 parent 的
children() 列表中删除;如果有孩⼦,则⾃动 delete 每⼀个孩⼦。Qt 保证没有 QObject 会被
delete 两次,这是由析构顺序决定的。

 不过也存在一些特殊情况:

如果 QObject 在栈上创建,Qt 保持同样的⾏为。正常情况下,这也不会发⽣什么问题。来看下⾯的代码⽚段:

作为⽗组件的 window 和作为⼦组件的 quit 都是 QObject 的⼦类(事实上,它们都是QWidget的⼦类,⽽QWidget 是 QObject 的⼦类)。这段代码是正确的,quit 的析构函数不会被调⽤两次,因为标准 C++ 要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作⽤域时,会先调⽤ quit 的析构函数,将其从⽗对象 window 的⼦对象列表中删除,然后才会再调⽤window 的析构函数。

但是如果我们调换一下对象的构造顺序:

情况⼜有所不同,析构顺序就有了问题。我们看到,在上⾯的代码中,作为⽗对象的 window 会⾸先被析构,因为它是最后⼀个创建的对象。在析构过程中,它会调⽤⼦对象列表中每⼀个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执⾏,在 window 析构之后,quit 也会被析构,因为 quit 也是⼀个局部变量,在超出作⽤域的时候当然也需要析构。但是,这时候已经是第⼆次调⽤ quit 的析构函数了,C++ 不允许调⽤两次析构函数,因此,程序崩溃了。

由此我们看到,Qt 的对象树机制虽然在⼀定程度上解决了内存问题,但是也引⼊了⼀些值得注意的事情。这些细节在今后的开发过程中很可能时不时跳出来烦扰⼀下,所以,我们最好从开始就养成良好习惯

 因此:在 Qt 中,尽量在构造的时候就指定 parent 对象,并且⼤胆在堆上创建。

Qt的坐标体系 

坐标体系:以左上⻆为原点(0,0),X向右增加,Y向下增加。 

这里跟数学的坐标体系是有点不一样的。

 对于嵌套窗⼝,其坐标是相对于⽗窗⼝来说的。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

自定义集成ESXI网卡驱动

需要的软件&#xff1a; ESXi-Customizer-v2.7.2 集成工具&#xff0c;可以将vib网卡驱动加载到镜像中&#xff0c;不用敲命令了 VIB 网卡驱动 根据自己网卡的型号自行下载 ESXi-Customizer-v2.7.2 软件地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1v5aI9T-Tl5…

Golang | Leetcode Golang题解之第559题N叉树的最大深度

题目&#xff1a; 题解&#xff1a; func maxDepth(root *Node) (ans int) {if root nil {return}queue : []*Node{root}for len(queue) > 0 {q : queuequeue nilfor _, node : range q {queue append(queue, node.Children...)}ans}return }

【JAVA基础】JVM双亲委派

JVM双亲委派 双亲委派机制为什么进行双亲委派&#xff1f;为什么要设计这种机制&#xff1f; 双亲委派机制 双亲委派是一个孩子向父亲方向&#xff0c;然后父亲向孩子方向的双亲委派过程总结&#xff1a;自下&#xff08;从 App 开始&#xff09;而上进行检查&#xff0c;自上…

Qt生成coredump文件(支持arm和x86架构)

简介&#xff1a; coredump一般都在执行文件崩溃时自动生成的&#xff0c;用来定位造成程序崩溃的原因。 ubuntu下的设置coredump步骤&#xff08;linux的x86架构&#xff09; 1、正常情况下coredump生成路径需要在root权限下才能设置生效&#xff0c;所以我们需要进入root模式…

探秘Sketch及其替代者:设计软件精选指南

Sketch是一款适用于macOS系统的专业矢量绘图应用软件&#xff0c;由荷兰公司Sketch B.V. 开发&#xff0c;于2010年9月7日首次发布&#xff0c;并在2012年获得苹果设计大奖。以下是对Sketch软件的具体介绍。 1、Sketch软件是什么 功能特点&#xff1a; 矢量编辑功能强大&…

初识网络原理

1.网络互联 网络互联就是将多台计算机连接在一起&#xff0c;完成数据共享。 数据共享本质就是网络数据传输&#xff0c;即计算机之间通过网络来传输数据&#xff0c;也称为网络通信。 根据网络互联的规模不同&#xff0c;可以划分为局域网和广域网。 1.1 局域网 局域网&am…

文章管理系统微信小程序ssm+论文源码调试讲解

第2章 关键技术简介 2.1 微信小程序 微信小程序&#xff0c;简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种全新的连接用户与服务的方式&#xff0c;可以快速访问、快速传播&#xff0c;并具有良好的使用体验[12]。 小程序的主要开发语言是JavaScript&#xff…

Python OpenCV孤立点检测

孤立点检测 在Python中使用OpenCV进行孤立点&#xff08;异常点&#xff09;检测&#xff0c;可以通过应用统计分析或者使用OpenCV的findContours和convexHull函数来识别。以下是一个简单的例子&#xff0c;使用OpenCV的findContours和convexHull来识别并绘制孤立点。 孤立点…

leetcode-15-三数之和

题解&#xff1a; 代码&#xff1a; 参考&#xff1a;leetcode-16-最接近的三数之和

PHP中小学优校管理系统小程序源码

&#x1f3eb; 中小学优校管理系统&#xff1a;打造教育新生态&#xff0c;赋能智慧校园 &#x1f3eb; &#x1f3f7;️ 开篇&#xff1a;为什么我们需要中小学优校管理系统&#xff1f; 在教育日新月异的今天&#xff0c;传统的管理模式已难以满足现代学校的需求。面对庞大…

Java poi 模板导出Word 带图片

Java poi 模板导出Word 带图片 重点&#xff01;&#xff01;&#xff01; 官方文档&#xff1a;https://deepoove.com/poi-tl/#_maven 最终效果 模板 其实内容都在官方文档里写的非常明白了 我这里只是抛砖引玉。 Maven依赖 <poi.version>4.1.2</poi.version>…

【JAVA毕业设计】基于Vue和SpringBoot的微服务在线教育系统

博主说明&#xff1a;本文项目编号 T 060 &#xff0c;文末自助获取源码 \color{red}{T060&#xff0c;文末自助获取源码} T060&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

泷羽sec学习打卡-Linux基础

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于Linux的那些事儿-Base 一、Linux-Base什么时openssl&#xff1f;有哪些加密参数&#xff1f;常用lin…

【6.2】位运算-解重复的DNA序列

一、题目 所有 DNA 都 由 一 系 列 缩 写 为 A &#xff0c; C &#xff0c; G 和 T 的 核 苷 酸 组 成 &#xff0c; 例如&#xff1a;"ACGAAT TCCG"。在研究DNA时&#xff0c;识别DNA中的重复序列有时会对研究非常有 帮助。 编写一个函数来找出所有目标子串&#…

Net.Core Mvc 添加 log 日志

1: 首先在 Nuget 安装插件 2&#xff1a;添加 log 配置 在项目中新创件一个文件夹 ConfigFile 在文件家里面添加 log4net.config log4net.config 里面写入 <?xml version"1.0" encoding"utf-8"?> <configuration><log4net><!--跟…

A030-基于Spring boot的公司资产网站设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

AG32 MCU与CPLD通过AHB总线交互

MCU与CPLD可以通过AHB或APB总线进行数据交互。APB总线通常连接低速设备&#xff0c;如串口&#xff0c;而AHB总线则用于连接高速设备&#xff0c;如RAM等。由于我们需要高速采集大量数据&#xff0c;因此选择使用AHB总线与CPLD进行交互。 地址范围 在地址设计中&#xff0c;C…

【学习笔记】PT协程-未完待续

单线程编程-协程 单线程&#xff0c;所有协程都是共享栈–换句话说&#xff1a;裸机 代码结构 十分精简 lc 有两个版本 文件说明lc-addrlabels.h使用GCC扩展语法实现的协程基础lc-switch.h使用switch语句实现的协程基础lc.h用于选择GCC语法还是switch语句实现pt.h基于lc.h实…

【python系列】python内置函数print()和input()

1.前言 正式开始学习python编程基础知识&#xff0c;首先要建立正确的学习姿势&#xff0c;什么姿势呢&#xff0c;当然不是躺着。首先要学会看语法&#xff0c;学习每一个内置函数都要先把语法和语义理解&#xff0c;再结合勤于练习。有些同学可能英语不太好&#xff0c;这里…

并发基础:(淘宝笔试题)三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC....”的字符串

🚀 博主介绍:大家好,我是无休居士!一枚任职于一线Top3互联网大厂的Java开发工程师! 🚀 🌟 在这里,你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人,我不仅热衷于探索一些框架源码和算法技巧奥秘,还乐于分享这些宝贵的知识和经验。 💡 无论你是刚刚踏…