描述
Qt对象树
是一种基于父子关系的对象管理机制,用于管理Qt应用程序中的所有对象。在Qt中,每个对象都可以拥有一个或多个子对象,并且每个子对象只能属于一个父对象。每个对象的所有权(也称为生存期)由其父对象控制。当父对象销毁时,它们会自动销毁其所有子对象,以确保在程序结束之前释放所有内存。
对象在对象树中组织自己。当you使用另一个对象作为父对象创建QObject
时,它被添加到父对象的children()
列表中,并在父对象被删除时被删除。事实证明,这种方法非常适合GUI对象的需要。例如,QShortcut(键盘快捷键)
是相关窗口的子窗口,因此当用户关闭该窗口时,快捷键也会被删除。
QWidget
是Qt Widgets
模块的基本类,它扩展了父子关系。子部件通常也成为子部件,即它显示在其父部件的坐标系统中,并被其父部件的边界以图形方式剪切。例如,当应用程序在关闭消息框后删除消息框时,消息框的按钮和标签也会被删除,正如我们所希望的那样,因为按钮和标签是消息框的子框。
程序员也可以自己删除子对象,将自己从父对象中移除。例如,当用户删除工具栏时,可能导致应用程序删除其QToolBar
对象之一,在这种情况下,工具栏的QMainWindow
父组件将检测到更改并相应地重新配置其屏幕空间。
调试函数QObject:: dumpobjectreree()
和QObject::dumpObjectInfo()
在应用程序看起来或行为异常时通常很有用。
如QObject:: dumpobjectreree()
:
this->dumpObjectTree();
如QObject::dumpObjectInfo()
:
checkBox->dumpObjectInfo();
实际应用
在实际应用中,可以通过以下几种方式创建对象树:
-
通过new运算符手动分配内存来创建对象,然后使用QObject的setParent()函数将它们移动到树中。
-
使用Qt的自动内存管理机制,例如Qt的容器类,这些类在使用时会自动管理对象的内存,使它们成为树中的子对象。
对象的构造和销毁顺序
当在堆上创建QObjects(即用new创建)时,可以以任何顺序从它们构造一个树,然后,树中的对象可以以任何顺序销毁。当树中的任何QObject被删除时,如果该对象有父对象,析构函数将自动从其父对象中删除该对象。如果对象有子对象,析构函数会自动删除每个子对象。无论销毁顺序如何,QObject都不会被删除两次。
当在堆栈上创建QObjects
时,同样的行为也适用。通常情况下,破坏的顺序不会造成问题。如下面的代码片段:
int main()
{
QWidget window;
QPushButton quit("Quit", &window);
...
}
父窗口和子窗口都是QObject
,因为QPushButton
继承了QWidget
,而QWidget
继承了QObject
。这段代码是正确的:quit
的析构函数不会被调用两次,因为c++语言标准(ISO/IEC 14882:2003)指定局部对象的析构函数以与其构造函数相反的顺序调用。因此,首先调用子进程的析构函数quit,并在调用window的析构函数之前将自己从父进程window中移除。
但是现在考虑一下如果我们交换构造顺序会发生什么,如下面代码所示:
QPushButton quit("Quit");
QWidget window;
quit.setParent(&window);
在这种情况下,破坏的顺序会引起问题。父类的析构函数首先被调用,因为它是最后创建的。然后调用它的子孩子quit的析构函数,这是不正确的,因为quit是一个局部变量。当quit随后超出作用域时,它的析构函数将被再次调用,这次是正确的,但是损害已经造成了。
示例
#include <QtWidgets>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget *mainWidget = new QWidget; // 创建主窗口 Widget
QVBoxLayout *layout = new QVBoxLayout(mainWidget); // 创建主窗口的布局管理器
QLabel *label = new QLabel("Hello Qt!"); // 创建标签对象
layout->addWidget(label); // 将标签对象添加到布局管理器中
QPushButton *button = new QPushButton("Click me!"); // 创建按钮对象
layout->addWidget(button); // 将按钮对象添加到布局管理器中
mainWidget->show(); // 显示主窗口
return app.exec(); // 进入 Qt 事件循环
}
如果希望将标签和按钮对象添加到主窗口的对象树中,可以使用QWidget的setParent()函数将它们添加为主窗口的子对象:
label->setParent(mainWidget);
button->setParent(mainWidget);
这样,当主窗口对象被销毁时,它们也会被自动销毁。
结论
努力不一定有收获,但是不努力一定会很舒服哦
。