假设我想创建一个对话框,我的主程序的一个孩子:
from PyQt4 import QtGui, QtCore
class WizardJournal(QtGui.QDialog):
def __init__(self, parent):
super(WizardJournal, self).__init__(parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.wizard = QtGui.QWidget()
self.ok_button = QtGui.QPushButton("OK", self)
self.vbox_global = QtGui.QVBoxLayout(self)
self.vbox_global.addWidget(self.ok_button)
self.paret.wizard.setLayout(self.vbox_global)
self.parent.wizard.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
parent = QtGui.QWidget()
obj = WizardJournal(parent)
sys.exit(app.exec_())
此对话框将由我的主程序打开和关闭。有关内存消耗的更好方法:
self.ok_button = QtGui.QPushButton("OK", self)
self.ok_button = QtGui.QPushButton("OK")
基本上,我想知道在创建窗口小部件时是否应该提及父窗口小部件。当我关闭此对话框时,如果在创建父窗口小部件时没有提及父窗口小部件,是否会从内存中释放确定按钮?
答案 0 :(得分:11)
根据您的示例当前结构的方式,对话框及其任何子窗口小部件在关闭时都不会被删除。
您可以通过将示例的结尾更改为以下内容来查看此内容:
app.exec_()
print('\n'.join(repr(w) for w in app.allWidgets()))
将提供这样的输出(一旦对话框关闭):
<__main__.WizardJournal object at 0x7fcd850f65e8>
<PyQt4.QtGui.QPushButton object at 0x7fcd850f6708>
<PyQt4.QtGui.QWidget object at 0x7fcd850f6558>
<PyQt4.QtGui.QDesktopWidget object at 0x7fcd850f6828>
<PyQt4.QtGui.QWidget object at 0x7fcd850f6678>
在PyQt中,你必须要知道对象可能有两种引用:一种在Python端(PyQt包装器对象),另一种在C ++端(底层Qt对象)。因此,要完全删除对象,您需要删除所有这些引用。
通常,Qt不会删除对象,除非您明确告诉它这样做。在使用父对象创建对话框时,您需要注意这一点,否则很容易产生内存泄漏。通常会看到这样编写的代码:
def openDialog(self):
dialog = MyDialog(self)
dialog.show()
乍一看看起来毫无害处 - 但是每次调用它时该方法都会创建一个新的对话框,而Qt最终会持续每一个(因为{{ 1}}关于C ++方面的参考)。避免这种情况的一种方法是重新编写方法,以便它只在Python端保留引用:
parent
但是如何处理模式对话框,必须拥有父级?在这种情况下,您可以像这样初始化对话框类:
def openDialog(self):
self.dialog = MyDialog()
self.dialog.show()
现在Qt会在关闭时自动删除对话框,并且还会递归删除所有子对象。这将留下一个空的PyQt包装器对象,它最终会被Python垃圾收集器删除。
因此,对于您的特定示例,我认为我会重新编写它看起来像这样:
class MyDialog(QtGui.QDialog):
def __init__(self, parent):
super(MyDialog, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
对话框类现在完全是自包含的,并且只有一个外部python引用它的实例。 (如果需要从对话框类中访问父窗口小部件,可以使用import sys
from PyQt4 import QtGui, QtCore
class WizardJournal(QtGui.QDialog):
def __init__(self, parent):
super(WizardJournal, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.initUI()
def initUI(self):
self.ok_button = QtGui.QPushButton("OK", self)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.ok_button)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
parent = QtGui.QWidget()
obj = WizardJournal(parent)
app.exec_()
print('\n'.join(repr(w) for w in app.allWidgets()))
)。
PS:当小部件被添加到布局时,它们将自动重新设置为任何顶级小部件最终包含布局的父级。因此,严格地说,没有必要在代码中为这些小部件显式设置父级。