【问题标题】:Proper way to cleanup widgets in pyqt在pyqt中清理小部件的正确方法
【发布时间】:2012-12-11 20:15:47
【问题描述】:

使用 PyQt4 时清理/删除小部件的“正确”或惯用方式是什么?

考虑以下代码:

choices = ['a', 'b', 'c']
checkboxes = []
layout = QtGui.QVBoxLayout()

dialog = MyDialog()

for c in choices:
    checkboxes.append(QtGui.QCheckBox(c)
    layout.addWidget(chkbox)

dialog.setLayout(layout)

for c in checkboxes:
    c.setParent(None)
    c.deleteLater()
    c = None

以上代码使用setParent()deleteLater(),并将对象设置为None。这些都是必要的吗?

另一种可能的情况是我有一个对话框,上面有一堆小部件,我想删除这些小部件并添加新的小部件。我不想“泄露”旧的小部件,但我不确定这样做的正确方法是什么。

在我看来,deleteLater() 可能永远不需要。它只是减少引用计数吗?如果是这样,只是将变量设置为 None 不会做同样的事情吗?

【问题讨论】:

    标签: pyqt pyqt4


    【解决方案1】:

    您应该记住的第一件事是为您的小部件使用父/子关系。当您这样做时,它们将归 Qt 所有,并在删除父级时自动清理所有子级。

    dialog = MyDialog()
    
    for c in choices:
        checkboxes.append(QtGui.QCheckBox(c, parent=dialog))
        layout.addWidget(chkbox)
    

    在这种情况下,当您删除对话框时,所有复选框都会被正确清除。这处理了您问题的一部分。我意识到当您将父级添加到布局时,您隐含地设置了父级。但是您不应该在删除之前清除该父级。它允许自动删除子级的父级关系。不是参考计数。引用方面将是一个 python 端的东西,当没有更多对它的引用时,它将被垃圾收集。

    deleteLater 非常重要,当您希望在控制返回事件循环时发生删除时使用。当您从布局中删除一些小部件并添加新小部件时,这也是删除小部件的安全方法:

    # clear a layout and delete all widgets
    # aLayout is some QLayout for instance
    while aLayout.count():
        item = aLayout.takeAt(0)
        item.widget().deleteLater()
    

    一旦此方法完成,这些小部件实际上将被删除。 deleteLater 也可用于删除当前正在发生插槽或事件的小部件。比如一个 QPushButton 可以在点击时自行删除。

    也不需要设置c = None。一旦删除父对象,并触发删除其所有子对象,递归地,您对该对象的 python 引用将无效。因此,您需要做的就是不再使用它们。如果它们在列表中,请清除该列表。访问它们会引发RuntimeError: wrapped C/C++ object of %S has been deleted,表示它们已被删除。

    【讨论】:

    • 在创建要添加到布局的所有对象时是否需要使用parent 参数?我意识到这可能更明确一点,但这是必需的吗?
    • 不,不是。如果您将它们直接添加到布局中,那么布局将使它们成为布局所有者的子级。
    • 参加聚会很晚,但我想我会补充一点——尽管使用parent 参数不是必要——这可能是一个好主意,因为它限制了代码的结构,并让其他人更容易看到预期的包含层次结构是什么。
    • @jdi 您说“访问它们会引发RuntimeError: wrapped C/C++ object 错误” - 我如何检查对象是否无效/已被删除?我需要一种方法来检查c 是否已被删除,但我不知道如何删除。请参阅我的问题:stackoverflow.com/questions/27420338/…
    • @memyself - 在不尝试访问方法并捕获 RuntimeError 的情况下检查它是否已被删除的唯一方法是使用 PyQt 的 sip 模块或 PySide 的 shiboken 模块。他们会允许你查询的指针被删除了。除此之外,您只需点击 objectName() 方法即可捕获错误。
    猜你喜欢
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 2021-04-23
    • 2018-06-19
    • 2017-06-09
    • 2021-10-08
    • 2012-04-16
    • 2021-06-15
    相关资源
    最近更新 更多