【问题标题】:PyQt: give parent when creating a widget?PyQt:创建小部件时给父母?
【发布时间】:2016-06-20 08:42:01
【问题描述】:

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

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

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

【问题讨论】:

    标签: python memory pyqt


    【解决方案1】:

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

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

    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 最终会保留其中的每一个(因为 @987654324 @C++ 端的参考)。避免这种情况的一种方法是重写该方法,使其仅在 Python 端保留一个引用:

    def openDialog(self):
        self.dialog = MyDialog()
        self.dialog.show()
    

    但是对于一个必须有父对象的模态对话框该怎么办呢?在这种情况下,您可以像这样初始化对话框类:

    class MyDialog(QtGui.QDialog):
        def __init__(self, parent):
            super(MyDialog, self).__init__(parent)
            self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    

    现在 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()))
    

    对话框类现在是完全独立的,只有一个外部 python 引用指向它的实例。 (如果您需要从对话框类中访问父窗口小部件,可以使用self.parent())。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2011-09-03
      • 2017-10-21
      • 1970-01-01
      相关资源
      最近更新 更多