【QT】概述补充——对象树
2.对象树
文章目录
- 2.对象树
- QObject 是以对象树的形式组织起来的
- QWidget 是能够在屏幕上显示的⼀切组件的父类
- 汉字编码方式与字节占用问题解析
- Qt 窗口坐标体系
在前面写第一个显示hello world
程序的时候,我们强调创建label
对象的时候一定要使用new
的方式在堆上创建变量,并且带了一个this
参数,下面解释原因。在 Qt 中创建很多对象的时候会提供⼀个 Parent 对象指针,下⾯来解释这个 parent 到底是⼲什么的。
QObject 是以对象树的形式组织起来的
-
当创建⼀个 QObject 对象时,会看到 QObject 的构造函数接收⼀个 QObject 指针作为参数,这个参数就是 parent,也就是⽗对象指针。比如:
QLabel* label = new QLabel(this);
此处通过new的方式创建对象,也就是为了把这个对象的生命周期,交给Qt的对象树来统一管理。在QT中,将这类对象创建在栈上而非堆上会导致严重问题。虽然栈上创建的对象也能编译运行,但会因提前销毁导致显示异常。例如,一个在构造函数中创建的栈对象QLabel,会在构造函数结束时立即销毁,导致界面无法显示该标签。
-
这相当于,在创建 QObject 对象时,可以提供⼀个其⽗对象,我们创建的这个 QObject 对象会⾃动添加到其⽗对象的 children() 列表
-
当⽗对象析构的时候,这个列表中的所有对象也会被析构。(注意,这⾥的⽗对象并不是继承意义上的父类)。所以:上述代码,在Qt中不会产生内存泄露。label对象会合适的时候被析构释放~~(虽然没有手动写delete,确实能释放)之所以能够把对象释放掉,主要是因为把这个对象是挂到了对象树上。
树形结构的核心优势在于能够统一释放内存,当父窗口关闭时,所有子对象都会被自动销毁。这种机制确保了界面元素的生命周期与窗口保持一致,避免出现控件提前销毁而窗口仍然存在的bug情况。
在QT编程中,对象树机制是管理内存的关键。通过将对象挂载到对象树上,QT能够自动管理对象的生命周期,避免内存泄漏。对象树是一个N叉树结构,类似于前端开发中的DOM树,用于组织界面上的各种控件元素。例如,一个典型QT界面可能包含QWidget作为根节点,下面包含QLabel、QPushButton和QListWidget等子节点,这些子节点又可以包含更多子节点。当父窗口关闭或销毁时,QT会自动销毁对象树上所有子对象,确保内存被正确释放。这种机制解决了手动管理内存的难题,特别是避免了对象提前销毁导致的界面显示问题。如果对象在栈上创建而非通过new创建,虽然代码能编译运行,但会导致对象在构造函数结束时就被销毁,造成界面显示异常。因此,在QT中推荐使用new创建对象并交给对象树管理,这是更科学合理的内存管理方式。
举例:创建一个我们自己的按钮继承QPushButton,定义构造函数和析构函数输出调试信息,就可以看到当按钮创建时调用析构函数,直接关闭窗口,按钮会调用析构函数
//mypushbutton.h
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H#include <QPushButton>
#include <QWidget>
class MyPushButton : public QPushButton
{
public:MyPushButton(QWidget* parent);~MyPushButton();
};#endif // MYPUSHBUTTON_H//mypushbutton.cpp
#include "mypushbutton.h"
#include <QDebug>MyPushButton::MyPushButton(QWidget* parent = nullptr) : QPushButton(parent)
{qDebug() << "MyPushButton() used!";
}MyPushButton::~MyPushButton()
{qDebug() << "~MyPushButton() used!";
}//Widget.cpp
#include "widget.h"
#include "ui_widget.h"#include "mypushbutton.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);MyPushButton *button = new MyPushButton(this);button->setText("按钮");
}Widget::~Widget()
{delete ui;
}
QWidget 是能够在屏幕上显示的⼀切组件的父类
QWidget 继承⾃ QObject ,因此也继承了这种对象树关系。⼀个孩⼦⾃动地成为⽗组件的⼀个⼦组件。因此,它会显⽰在⽗组件的坐标系统中,被⽗组件的边界剪裁。例如,当⽤⼾关闭⼀个对话框的时候,应⽤程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该⼀起被删除。事实就是如此,因为这些都是对话框的⼦组件
当然,我们也可以⾃⼰删除⼦对象,它们会⾃动从其⽗对象列表中删除。⽐如,当我们删除了⼀个⼯具栏时,其所在的主窗⼝会⾃动将该⼯具栏从其⼦对象列表中删除,并且⾃动调整屏幕显⽰
汉字编码方式与字节占用问题解析
计算机中汉字占用的字节数取决于所使用的编码方式,不能简单地回答一个固定数字。英文字母通过ASCII码表用数字表示,一个字节足够。中文汉字数量庞大,常用字约4000个,加上生僻字总数约6万个,需要更大的编码表来表示。不同的组织可以制定不同的汉字编码表,导致同一个汉字可能有多种表示方式。目前主流的汉字编码方式有两种:GBK和UTF-8。GBK主要在中国大陆使用,使用两个字节表示一个汉字,Windows简体中文版默认使用GBK编码。UTF-8是一种变长编码,表示一个符号可能使用2-4个字节,但一个汉字通常使用三个字节表示。编码方式不匹配是导致程序中出现乱码的根本原因,因为同一个汉字在不同编码方式下对应的二进制表示不同。
-
Qt中有一个东西,QString,是可以帮助我们自动的处理编码方式的。不止是QString,Qt也提供了专门用来打印日志的工具,也能自动处理编码方式
-
Qt中提供了一个qDebug0工具,借助这个,就可以完成打印日志的过程,很好的处理字符编码,(不需要程序员关注了,内部帮咱们搞好了)
#include <QDebug> qdebug() << "....."
-
后续再Qt中,如果想通过打印日志的方式,输出一些调试信息,都优先使用qDebug.虽然使用cout也行,但是cout对于编码的处理不太好,在
windows上容易出现乱码(如果是Linux使用QtCreator,一般就没事了,Linux默认的编码一般都是utf8)
Qt 窗口坐标体系
坐标体系:以左上⻆为原点(0,0),X向右增加,Y向下增加。 对于嵌套窗⼝,其坐标是相对于⽗窗⼝来说的
nux使用QtCreator,一般就没事了,Linux默认的编码一般都是utf8)