【Qt】Qt界面构建与对象管理:从 “Hello World“ 到内存释放

ops/2024/9/20 1:33:23/ 标签: qt, 开发语言, c++

文章目录

  • 1. 通过图形化界面创建控件
  • 2. 通过纯代码方式创建控件
  • 3. 对象树管理与内存管理
  • 小结:

在软件开发中,构建用户界面是至关重要的一步。Qt作为一个跨平台的C++框架,提供了强大的界面构建工具和对象树管理机制,使得界面开发变得简单高效。本文将介绍两种实现 “Hello World” 界面的方法:一种是通过图形化界面创建控件,另一种是通过纯代码方式创建控件,并探讨了Qt框架中的对象树管理机制与前端开发中的DOM对象树的类比。

1. 通过图形化界面创建控件

Qt提供了可视化设计工具,通过拖拽控件、设置属性和信号槽等方式,可以快速构建用户界面。下面是通过图形化界面创建一个显示 “Hello World” 的控件的步骤:

  1. 打开Qt Creator,创建一个新的Qt Widgets Application项目。
  2. 在设计模式下,从左侧的控件库中拖拽一个Label控件到界面上。
  3. 在属性编辑器中设置Label的文本为 “Hello World”。
  4. 编译运行程序,即可看到界面上显示了 “Hello World”
    在这里插入图片描述

2. 通过纯代码方式创建控件

虽然图形化界面设计工具方便直观,但有时候我们也需要通过纯代码的方式来创建控件。下面是通过纯代码方式在Qt中创建一个显示 “Hello World” 的控件的示例代码:

// widget.cpp
// 一般通过代码来构造界面的时候
// 通常会把构造界面放到 Widget/MainWindow 的构造函数中
#include "widget.h"
#include "ui_widget.h"#include<QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 创建对象的时候可以在栈上创建栈上,也可以在堆上创建// QLabel label(this) // 在栈上创建会,一下马上消失// 更推荐这种直接在堆上面创建的方式QLabel* label = new QLabel(this); //给当前的 label对象,指定一个父对象label->setText("hello world"); // 在QString 中也提供了C风格字符串作为参数的构造函数.// 不显式构造QString,上述代码中,C风格字符串也会隐式构造成QString对象.
}Widget::~Widget()
{delete ui;
}

Qt在早期确实为了解决C++标准库的不足而引入了自己的一套基础类和容器类,以便支持Qt框架的开发。下面是一些常用的Qt自带容器类及其功能:

  1. QString:用于处理字符串,支持 Unicode 字符串,提供了丰富的字符串操作方法。
  2. QVector:动态数组,类似于std::vector,但提供了更多的功能和操作。
  3. QList:链表,类似于std::list,但也提供了额外的操作和功能。
  4. QMap:字典,类似于std::map,用于键值对的映射。
  5. QSet:集合,类似于std::set,用于存储不重复的元素。

这些Qt自带的容器类在Qt的API中被广泛使用,因此在Qt开发中,通常会见到这些类的使用。虽然这些类与标准库中的类功能类似,但它们通常提供了更多的特性和对Qt框架的更好的支持。

在使用这些Qt容器类时,可以方便地进行与标准库容器类的互操作,例如QString和std::string之间的转换。同时,Qt的容器类内部已经处理了一些字符编码的细节,使得处理
Unicode 字符串更为方便。相比之下,标准库中的std::string可能需要额外的处理来支持特定的字符编码。

总的来说,Qt提供的这些容器类为开发者提供了更多选择,同时也更好地与Qt框架集成,使得开发过程更加高效和便捷。

// 更推荐这种直接在堆上面创建的方式
QLabel* label = new QLabel(this); //给当前的 label对象,指定一个父对象 
// 此处通过new的方式创建对象,也就是为了把这个对象的声明周期,交给Qt的对象树统一管理。

3. 对象树管理与内存管理

Qt框架中的对象树管理机制类似于前端开发中的DOM对象树,Qt中也是类似,也是搞了一个对象树,也是N叉树,把界面上的各种元素组织起来了 。通过将控件添加到父控件中,Qt能够自动管理控件的生命周期,从而避免内存泄漏。在上述示例中,我们给QLabel控件指定了父对象为当前的Widget,这样当Widget被销毁时,其子控件也会被自动销毁,从而确保内存的正常释放。
在这里插入图片描述

证明对象是被自动销毁了的:
新建一个C++类:
在这里插入图片描述
在这里插入图片描述
Qt Creator 是帮我们生成了一些代码,但是没有完全生成,头文件没给咱们自动包含,只能自己手动包含了。

在这里插入图片描述

// widget.cpp
#include "widget.h"
#include "ui_widget.h"#include "mylabel.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 使用自己的定义的 Mylabel 代替原来的 QLabel, 所谓的“继承” 本质上是扩展,保持原来的功能不变的基础上,// 给对象扩展出一个析构函数,通过这个析构函数,答应一个自定义日志,方便咱们观察运行效果。MyLabel* label = new MyLabel(this);label->setText("hello world");
}Widget::~Widget()
{delete ui;
}
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;
};
#endif // WIDGET_H
// mylabel.cpp
#include "mylabel.h"
#include <iostream>// QLabel(parent) 就是这个调用父类构造函数,调用这个,才能让咱们自己类的对象加入到Qt对象树中
MyLabel::MyLabel(QWidget* parent) : QLabel(parent)
{}MyLabel::~MyLabel()
{std::cout << "MyLable 被销毁!" << std::endl;
}
// mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H#include <QLabel>class MyLabel : public QLabel
{
public:// 构造函数使用带 QWidget* 版本的// 这样才能保证咱们自己的对此昂能够加到对象树上MyLabel(QWidget* parent);~MyLabel();
};#endif // MYLABEL_H

当关闭窗口的时候
在这里插入图片描述
在关闭窗口时,预期输出 “MyLabel 被销毁!”,但实际上输出了乱码。这是因为输出的中文字符在计算机中存储时所占字节数取决于字符集的不同。

在计算机中,一个汉字,占几个字节?
针对这个问题,只要你回答出一个具体的数字,就一定是错的 !!
前提条件:当前中文编码使用的是哪种方式(字符集) 计算机存的其实是二进制数字 英文字母,怎么表示的 ?
ASCII码表,规定了每个字符,都有一个对应的数字来表示 。
目前,表示汉字字符集,主要是两种方式.

  1. GBK.(中国大陆)使用2个字节表示一个汉字. Windows 简体中文版,默认的字符集就是GBK.
  2. UTF-8 / utf8 但是在utf8中,一个汉字,一般是3个字节. Linux 默认就是 utf8 变长编码.表示一个符号,使用的字节数有变化,2-4

出现乱码的原因就是:
如果你字符串本身是utf8 编码的,但是终端(控制台)是按照gbk的方式来解析显示的,此时就会出现乱码。
(拿着utf8这里的数值,去查询gbk的码表),此时就会出现乱码了 !!

std::cout << "MyLable 被销毁!" << std::endl;

在这里插入图片描述

Qt中有一个好东西,QString:是可以帮助我们自动的处理编码方式的。
不止是QString,Qt也提供了专门用来打印日志的工具,也能自动处理编码方式,Qt中提供了一个qDebug()工具,借助这个,就可以完成打印日志的过程.很好的处理字符编码。(不需要程序员关注了,内部帮咱们搞好了)

在这里插入图片描述
这样就正常了
在这里插入图片描述

后续再Qt中,如果想通过打印日志的方式,输出一些调试信息,都优先使用 qDebug。虽然使用 cout 也行,但是 cout 对于编码的处理不太好,在 windows 上容易出现乱码(如果是Linux 使用 Qt Creator,一般就没事了,Linux默认的编码一般都是 utf8) 使用qDebug,还有一个好处 ,打印的调试日志,是可以统一进行关闭的 !
输出的日志,是开发阶段,调试程序的时候,使用的。 如果你的程序发布给用户,不希望用户看到这些日志的 ! qDebug 还可以通过编译开关,来实现一键式关闭 。

小结:

  1. QLabel类:能够在界面上显示字符串,通过setText()方法设置显示内容,参数为QString。
  2. 内存泄漏/资源泄漏:在Qt中需要注意及时释放对象,防止内存泄漏或者文件资源泄漏。
  3. 对象树:Qt通过对象树来管理界面控件对象的释放。推荐使用new方式在堆上创建对象,并指定父对象,在构造函数中将对象挂到对象树上,以便统一释放对象。创建的时候,在构建函数中,指定父对象(此时才会挂到树上),如果你的对象没有挂到对象树上,就必须记得手动释放
  4. 继承扩展:通过继承Qt内置的类,可以对现有控件进行扩展。例如,可以创建自定义类MyLabel,继承自QLabel,并重写析构函数,在其中加入日志记录以观察对象释放过程。继承本质上是对现有代码进行扩展,可以重写控件中的功能以实现个性化需求。
  5. 乱码问题和字符集:在处理中文字符时,需要注意字符集的问题。常见的字符集有GBK和UTF-8,输出乱码可能是因为字符集不匹配导致的。
  6. 日志打印:在Qt中推荐使用qDebug()函数打印日志信息,而不是使用cout。qDebug()能够自动处理字符编码,方便统一进行日志输出管理,同时能够通过编译开关一键式关闭调试信息输出。

http://www.ppmy.cn/ops/7748.html

相关文章

李宏毅2022机器学习/深度学习 个人笔记(1)

本系列用于推导、记录该系列视频中本人不熟悉、或认为有价值的知识点 本篇记录第一讲&#xff08;选修&#xff09;&#xff1a;神奇宝贝分类 如图&#xff0c;为了估算某个样本属于某类的概率&#xff0c;在二分类问题中&#xff0c;我们需要计算红框所示的4个参数&#xff0…

Linux Centos 9保姆级系统安装教程

文章目录 下载Centos 9镜像文件安装Centos 下载Centos 9镜像文件 清华大学源网址https://mirrors.tuna.tsinghua.edu.cn/ 安装Centos 所需软件&#xff1a;VMware Workstation 16 Pro 版本里面没有Centos 9&#xff1b; 这里我们选择Centos 7同样可以使用 用户设置

Elasticsearch:使用向量化和 FFI/madvise 加速 Lucene

作者&#xff1a;来自 Elastic Chris Hegarty 在 Lucene 领域&#xff0c;我们一直热切地采用新版本 Java 的功能。这些功能使 Lucene 更接近 JVM 和底层硬件&#xff0c;从而提高了性能和稳定性。这使得 Lucene 保持现代化和具有竞争力。 Lucene 的下一个主要版本&#xff0…

RIME-SVM,基于RIME寒冰优化算法优化SVM支持向量机回归预测 (多输入单输出)-附代码

支持向量机&#xff08;SVM&#xff09; 支持向量机&#xff08;SVM&#xff09;是一种广泛用于分类和回归的强大监督学习算法。在回归任务中&#xff0c;特别是在SVM被用作支持向量回归&#xff08;SVR&#xff09;时&#xff0c;目标是找到一个函数&#xff0c;这个函数在给…

Apache Hadoop 输入格式示例

目录 TextInputFormat 示例 SequenceFileInputFormat 示例 总结 TextInputFormat 示例 描述: TextInputFormat 是 Hadoop 中使用最广泛的输入格式之一&#xff0c;适用于纯文本文件。它将文件按行划分&#xff0c;把每一行的起始偏移量作为键&#xff08;key&#xff09;&am…

JDBC学习

DriverManager&#xff08;驱动管理类&#xff09; Drivermanager的作用有&#xff1a; 1.注册驱动&#xff1b; 2.获取数据库连接 Class.forName("com.mysql.cj.jdbc.Driver"); 这一行的作用就是注册Mysql驱动&#xff08;把我们下载的jar包加载到内存里去&…

实现 Android 设备屏幕录制的批处理脚本

在本文中&#xff0c;我们将介绍如何使用批处理脚本来实现在 Android 设备上进行屏幕录制&#xff0c;并将录制的视频文件传输到计算机上。这个脚本利用了 Windows 的批处理脚本和 Android 的 adb 工具。 背景 在进行 Android 应用开发、教学演示或问题排查时&#xff0c;我们…

毕业设计——基于ESP32的智能家居系统(语音识别、APP控制)

ESP32嵌入式单片机实战项目 一、功能演示二、项目介绍1、功能演示2、外设介绍 三、资料获取 一、功能演示 多种控制方式 ① 语音控制 ②APP控制 ③本地按键控制 ESP32嵌入式单片机实战项目演示 二、项目介绍 1、功能演示 这一个基于esp32c3的智能家居控制系统&#xff0c;能实…

使用51单片机控制T0和T1分别间隔1秒2秒亮灭逻辑

#include <reg51.h>sbit LED1 P1^0; // 设置LED1灯的接口 sbit LED2 P1^1; // 设置LED2灯的接口unsigned int cnt1 0; // 设置LED1灯的定时器溢出次数 unsigned int cnt2 0; // 设置LED2灯的定时器溢出次数// 定时器T0 void Init_Timer0() {TMOD | 0x01;; // 定时器…

三、Flask模型基础

ORM 创建模型 # exts.py&#xff1a;插件管理 # 扩展的第三方插件 # 1.导入第三方插件 from flask_sqlalchemy import SQLAlchemy # ORM插件 from flask_migrate import Migrate # 2. 初始化 db SQLAlchemy() # ORM migrate Migrate() # 数据迁移 # 3. 和app对象绑定 def…

Flink的安装、项目创建、任务打包和部署完整实现,任务实现使用JAVA语言

Flink资源下载地址 Flink安装包下载地址 一、本地模式安装Flink 1、在Linux服务上&#xff0c;创建flink文件夹 mkdir flink 2、上传文件并解压 tar -zxvf flink-1.14.6-bin-scala_2.11.tgz 解压完成后&#xff0c;如图&#xff1a; 3、启动Flink 进入到解压目录下&#x…

Css切换不同窗口

代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Title</title></head><style>/*label {*//* display: block;*//*}*/* {padding: 0;margin: 0;}body {height: 100vh;backgroun…

设计模式之原型模式

1、简单介绍 原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它通过复制现有的实例来创建新对象&#xff0c;而不是通过调用类的构造函数来创建新实例。这种模式适用于需要快速复制大量相同或相似对象&#xff0c;或者创建对象需要消耗大量…

【图论 单源最短路】100276. 最短路径中的边

本文时间知识点 单源最短路 图论知识汇总 LeetCode100276. 最短路径中的边 给你一个 n 个节点的无向带权图&#xff0c;节点编号为 0 到 n - 1 。图中总共有 m 条边&#xff0c;用二维数组 edges 表示&#xff0c;其中 edges[i] [ai, bi, wi] 表示节点 ai 和 bi 之间有一条…

前端nodead面试题

1.CSR和SSR分别是什么&#xff1f; CSR是客户端渲染&#xff0c;客户端访问网站时&#xff0c;服务器向客户端发送Html文档&#xff0c;让浏览器去渲染。其中像js,图片等还需要再次发请求。就是要啥给啥绝不多给。 缺点&#xff1a;不利于SEO&#xff0c;首次加载速度慢&…

Vue-router的动态路由:获取传递的值

Vue.js是一款流行的JavaScript框架&#xff0c;用于构建单页面应用程序。它提供了许多有用的功能&#xff0c;其中之一是Vue-router&#xff0c;它允许您轻松地管理应用程序的路由。Vue-router支持动态路由&#xff0c;这意味着您可以在路由中使用变量&#xff0c;并在组件中访…

Redis入门

1.初始Redis Redis是一种键值型的NoSql数据库&#xff0c;这里有两个关键字&#xff1a; 键值型 NoSql 其中键值型&#xff0c;是指Redis中存储的数据都是以key、value对的形式存储&#xff0c;而value的形式多种多样&#xff0c;可以是字符串、数值、甚至json&#xff1a;…

Excel数据处理:动态数据分析报表、单元格数字格式、使用排序工具

1、在生成数据透视表之后选中一个单元格&#xff0c;点击插入&#xff0c;在图表中选择一个自己想要的图表。&#xff08;生成可视化的图表&#xff09; 2、在分析中找到切片器&#xff0c;通过点击切片器可以即时变换生成不同的可视化图&#xff0c;可以右键切片器选择关联两个…

初始化Git仓库时应该运行哪个命令?

文章目录 初始化Git仓库时&#xff0c;你应该运行git init这个命令。这个命令的作用是在你当前所在的目录里创建一个新的Git仓库。这样&#xff0c;你就可以在这个目录里开始使用Git来管理你的文件了。 下面我给你举个详细的例子来说明一下&#xff1a; 首先&#xff0c;你需要…

【从浅学到熟知Linux】基础IO第一弹=>C语言文件操作接口、文件系统调用、文件描述符概念及分配规则

&#x1f3e0;关于专栏&#xff1a;Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 C语言文件接口回顾系统文件概念与接口文件基本概念系统接口openreadwritecloselseek 什么是当前路径 文件描…