使用 Qt 框架构建 GUI 界面的程序
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent) //这里的parent的意思是父级指针
: QWidget(parent) //调用父类的构造函数
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel* lable = new QLabel(this); //在堆上创建一个QLabel对象
lable->setText("hello world"); //调用对象的显示方法
}
Widget::~Widget()
{
delete ui;
}
对象树
提示:这里可以添加要学的内容
在qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个Parent指针是干什么的:
(1)QObject是以对象树的形式组织起来的
当创建一个对象QObject对象时,会看到QObject的构造函数接收一个QObject指针为参数,这个参数就是Parent,也就是父对象指针。这相当于,在创建QObject对象时,可以提供一个其父对象(指定父亲),我们创建的这个QObject对象会自动添加到其父对象的children()列表
(2)当父对象析构的时候,其父对象的children()列表中的所有对象也会被析构(注意这里的父对象并不是继承意义上的父类)。形象化的解释就是当释放窗口时,窗口内的组件对象也会被释放,这是合理的
(3)因此可以在代码中肆意创建对象,只要指定父对象,父对象包含管理释放(析构),那么子对象在父对象析构的时候会自动析构
(4) 对象树中,析构的顺序和构造的顺序是相反的
代码感受对象树
我们自己先创建一个ObjectTree文件,在这个文件里面添加一个C++的MyLabel类
因为我们要使用QLabel类,需要将自己的MyLabel类继承QLabel,自己写构造函数和析构函数
MyLabel完善之后,我们就可以在widget.cpp里面编写代码了
QWidget是widget的父亲,MyLabel是widget的儿子,这样析构widget对象的时候会自动析构MyLabel对象
当我们关闭这个窗体的时候,会看见自己定义的MyLabel类的析构被调用
对象树:这个概念非常好理解。因为 QObject 类就有一个私有变量 QList<QObject *>,专门存储这个类的子孙后代们。比如创建一个 QObject 并指定父对象时,就会把自己加入到父对象的 children() 列表中,也就是 QList<QObject *> 变量中。
使用对象树模式有什么好处?
提示:这里可以添加计划学习的时间
好处就是:当父对象被析构时子对象也会被析构。从一定程度上讲,简化了内存回收机制。
举个例子,有一个窗口 Window,里面有 Label标签、TextEdit文本输入框、Button按钮这三个元素,并且都设置 Window 为它们的父对象。这时候我做了一个关闭窗口的操作,作为程序员的你是不是自然想到将所有和窗口相关的对象析构啊?古老的办法就是一个个手动 delete 呗。是不是很麻烦?Qt 运用对象树模式,当父对象被析构时,子对象自动就 delete 掉了,不用再写一大堆的代码了。
所以,在我点击该运行程序的X后,系统会根据这个树状的结构,释放掉整个结构的内存。
对象树的问题(代码示例)
#include "widget.h"
#include <QApplication>
#include<QLabel>
#include<QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton button;
Widget w;
button.setParent(&w);
button.setText("QT崩溃");
w.show();
return a.exec();
}
在本例中,button和w按照顺序存放在栈里,而我们栈有先进后出的特性,正因如此,我们的程序结束后,系统会先释放w的内存,再释放button的内存,在释放w的内存时候由于 button变量绑定了父变量w(button.setParent(&w)😉,button也会和w一起释放,因此button在本例中会进行两次释放,从而导致奔溃
中创建对象的时候会提供一个 Parent对象指针(可以查看类的构造函数),下面来解释这个 parent 到底是干什么的。
QObject 是以对象树的形式组织起来的。当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。这相当于,在创建 QObject 对象时,可以提供一个其父对象,我们创建的这个 QObject 对象会自动添加到其父对象的 children () 列表。当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)
QWidget 是能够在屏幕上显示的一切组件的父类。QWidget 继承自 QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
Qt 引入对象树的概念,在一定程度上解决了内存问题。
(1)当一个 QObject 对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
(2)任何对象树中的 QObject 对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的 children () 列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有 QObject 会被 delete 两次,这是由析构顺序决定的。