PyQt:在创建窗口小部件时给父项?

时间:2016-06-20 08:42:01

标签: python memory pyqt

假设我想创建一个对话框,我的主程序的一个孩子:

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")

基本上,我想知道在创建窗口小部件时是否应该提及父窗口小部件。当我关闭此对话框时,如果在创建父窗口小部件时没有提及父窗口小部件,是否会从内存中释放确定按钮?

1 个答案:

答案 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:当小部件被添加到布局时,它们将自动重新设置为任何顶级小部件最终包含布局的父级。因此,严格地说,没有必要在代码中为这些小部件显式设置父级。