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

JPF*_*oia 5 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_())
Run Code Online (Sandbox Code Playgroud)

该对话框将由我的主程序打开和关闭.有关内存消耗的更好方法:

  • self.ok_button = QtGui.QPushButton("OK", self)
  • self.ok_button = QtGui.QPushButton("OK")

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

ekh*_*oro 14

鉴于您的示例当前的结构方式,对话框及其任何子窗口小部件在关闭时都不会被删除.

您可以通过将示例的结尾更改为如下所示来查看:

app.exec_()
print('\n'.join(repr(w) for w in app.allWidgets()))
Run Code Online (Sandbox Code Playgroud)

这将给出这样的输出(一旦对话框关闭):

<__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>
Run Code Online (Sandbox Code Playgroud)

在PyQt中,你必须要知道对象可能有两种引用:一种是Python端(PyQt包装器对象),另一种是C++端(底层Qt对象).因此,要完全删除对象,您需要删除所有这些引用.

通常,Qt不会删除对象,除非您明确告诉它这样做.在使用父对象创建对话框时,您需要注意这一点,否则很容易产生内存泄漏.看到这样编写的代码很常见:

def openDialog(self):
    dialog = MyDialog(self)
    dialog.show()
Run Code Online (Sandbox Code Playgroud)

乍一看看起来很无害 - 但是每次调用它时该方法都会创建一个新的对话框,Qt最终将继续保持它们中的每一个(因为parentC++方面的引用).避免这种情况的一种方法是重新编写方法,以便它只在Python端保留引用:

def openDialog(self):
    self.dialog = MyDialog()
    self.dialog.show()
Run Code Online (Sandbox Code Playgroud)

但是如何处理必须拥有父级的模态对话框呢?在这种情况下,您可以像这样初始化对话框类:

class MyDialog(QtGui.QDialog):
    def __init__(self, parent):
        super(MyDialog, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
Run Code Online (Sandbox Code Playgroud)

现在,Qt会在关闭时自动删除对话框,并且还会递归删除所有子对象.这将留下一个空的PyQt包装器对象,它最终会被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()))
Run Code Online (Sandbox Code Playgroud)

对话框类现在完全是自包含的,并且只有一个外部python引用它的实例.(如果需要从对话框类中访问父窗口小部件,则可以使用self.parent()).

PS:当小部件被添加到布局时,它们将自动重新设置为任何顶级小部件最终包含布局的父级.因此,严格来说,没有必要在代码中为这些小部件显式设置父级.