警告
本节包含从C++自动翻译到Python的代码片段,可能包含错误。
对象树与所有权¶
关于用于描述Qt中对象所有权的父子模式的信息。
概述¶
QObjects 在对象树中组织自己。当你创建一个以另一个对象为父对象的 QObject 时,它会被添加到父对象的 children() 列表中,并在父对象被删除时被删除。事实证明,这种方法非常适合 GUI 对象的需求。例如,QShortcut(键盘快捷键)是相关窗口的子对象,因此当用户关闭该窗口时,快捷键也会被删除。
QQuickItem,Qt Quick 模块的基本视觉元素,继承自 QObject,但有一个与 ** QObject parent 不同的 visual parent 概念。一个项目的视觉父级不一定与其对象父级相同。有关更多详细信息,请参阅 Qt Quick 中的概念 - 视觉父级。
QWidget,Qt Widgets模块的基础类,扩展了父子关系。一个子控件通常也会成为一个子部件,即它在父部件的坐标系中显示,并在图形上被父部件的边界裁剪。例如,当应用程序在关闭后删除一个消息框时,消息框的按钮和标签也会被删除,正如我们所期望的那样,因为按钮和标签是消息框的子控件。
你也可以自己删除子对象,它们会从它们的父对象中移除自己。例如,当用户移除工具栏时,可能会导致应用程序删除其一个QToolBar对象,在这种情况下,工具栏的QMainWindow父对象会检测到变化并相应地重新配置其屏幕空间。
调试函数 dumpObjectTree() 和 dumpObjectInfo() 在应用程序看起来或行为异常时通常很有用。
QObjects的构造/销毁顺序¶
当QObjects在堆上创建时(即使用new创建),可以以任何顺序从它们构建树,之后,树中的对象可以以任何顺序销毁。当树中的任何QObject被删除时,如果该对象有父对象,析构函数会自动将该对象从其父对象中移除。如果该对象有子对象,析构函数会自动删除每个子对象。无论销毁的顺序如何,都不会有QObject被删除两次。
当QObjects在栈上创建时,同样的行为适用。通常,销毁的顺序仍然不会造成问题。考虑以下代码片段:
if __name__ == "__main__": window = QWidget() quit = QPushButton("Quit", window) ...
父对象 window 和子对象 quit 都是 QObjects,因为 QPushButton 继承自 QWidget,而 QWidget 继承自 QObject。这段代码是正确的:quit 的析构函数不会被调用两次,因为 C++ 语言标准 (ISO/IEC 14882:2003) 规定局部对象的析构函数按照其构造函数的相反顺序调用。因此,子对象 quit 的析构函数首先被调用,并在父对象 window 的析构函数被调用之前,将自己从其父对象 window 中移除。
但现在考虑如果我们交换构造顺序会发生什么,如第二个代码片段所示:
if __name__ == "__main__": quit = QPushButton("Quit") window = QWidget() quit.setParent(window) ...
在这种情况下,销毁的顺序会导致问题。父类的析构函数首先被调用,因为它是最后创建的。然后它调用其子类的析构函数quit,这是不正确的,因为quit是一个局部变量。当quit随后超出作用域时,它的析构函数再次被调用,这次是正确的,但损害已经造成。