PyQt:在创建小部件时给父母? [英] PyQt: give parent when creating a widget?

查看:47
本文介绍了PyQt:在创建小部件时给父母?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's assume I want to create a dialog box, a child of my main program:

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_())

这个对话框会被我的主程序打开和关闭.什么是更好的内存消耗:

This dialog box will be opened and closed by my main program. What is better regarding memory consumption:

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

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

Basically, I would like to know if I should mention the parent widget when I create a widget. When I will close this dialog box, will the OK button be released from memory if I didn't mention the parent widget when I created it ?

推荐答案

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

Given the way your example is currently structured, neither the dialog nor any of its child widgets will be deleted when it is closed.

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

You can see this by changing the end of the example to look like this:

app.exec_()
print('\n'.join(repr(w) for w in app.allWidgets()))

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

which will give output like this (once the dialog is closed):

<__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 对象).因此,要完全删除一个对象,您需要删除所有这些引用.

In PyQt, you have to be aware that there may be two kinds of reference held for a object: one on the Python side (the PyQt wrapper object) and one on the C++ side (the underlying Qt object). So to fully delete an object, you need to remove all of these references.

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

In general, Qt does not delete objects unless you explictly tell it to do so. This is something you need to be aware of when creating dialogs with a parent, because it is very easy to produce a memory leak otherwise. It is common to see code written like this:

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

乍一看似乎无害 - 但该方法每次调用时都会创建一个新对话框,并且 Qt 最终会保留每个对话框(因为 parent 参考 C++ 端).避免这种情况的一种方法是重新编写该方法,使其仅在 Python 端保留一个引用:

Which looks harmless at first glance - but the method will create a new dialog every time it is called, and Qt will end up holding on to every single one of them (because of the parent reference on the C++ side). One way to avoid this is to re-write the method so that it only keeps a reference on the Python side:

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

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

But what to do about a modal dialog, which must have a parent? In that case, you could initialise the dialog class like this:

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

现在 Qt 会在对话框关闭时自动删除对话框,并且还会递归删除其所有子对象.这只会留下一个空的 PyQt 包装器对象,它将(最终)被 Python 垃圾收集器删除.

And now Qt will automatically delete the dialog when it is closed, and also recursively delete all of its child objects as well. This will just leave behind an empty PyQt wrapper object, which will (eventually) be removed by the Python garbage-collector.

所以对于您的特定示例,我想我会重新编写它,使其看起来像这样:

So for your particular example, I think I would re-write it to look something like this:

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()).

The dialog class is now completely self-contained, and there is only one external python reference to the instance of it. (If you need to access the parent widget from within the dialog class, you can use self.parent()).

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

PS: when widgets are added to a layout, they will be automatically re-parented to whatever top-level widget eventually contains the layout. So, strictly speaking, it is not necessary to explicitly set a parent for such widgets in your code.

这篇关于PyQt:在创建小部件时给父母?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆