gpt4 book ai didi

PyQt4 setParent vs deleteLater

转载 作者:行者123 更新时间:2023-12-04 04:04:47 25 4
gpt4 key购买 nike

我有一个布局,我添加了很多自定义小部件,例如 layout.addWidget(widget) .稍后我想删除所有这些自定义小部件并添加新小部件。当谈到 deleteLater 时,我对执行此操作的最佳方法感到困惑。和 setParent(None) .例如,这是我为布局中的所有小部件调用的清理函数:

def _removeFilterWidgetFromLayout(self, widget):
"""Remove filter widget"""

self._collection_layout.removeWidget(widget)
widget.setParent(None)
widget.deleteLater()

我怀疑并非所有这些行都需要正确清理小部件使用的内存。我不确定 C++ 和 Python 对 widget 的引用发生了什么。 .

以下是我对 PyQt 中 QObjects 的 C++ 和 Python 引用的理解。

我相信,当您将小部件添加到布局时,小部件将成为布局的子级。所以,如果我调用 removeWidget然后父关系被打破,所以我必须自己清理 C++ 和 Python 引用,因为小部件没有其他父级。调用 setParent是删除与布局的父关系的显式方法。调用 deleteLater旨在处理 C++ 引用。

Python 引用被垃圾收集,因为 widget变量超出范围,并且没有其他 Python 对象指向 widget .

我需要调用 setParentdeleteLater或会 deleteLater足以正确清理这个吗?

作为旁注,我发现调用 setParent(None)在这种情况下是一个非常昂贵的函数调用。通过删除这个调用,我可以大大加快我的整个清理过程。我不确定 deleteLater足以正确清理所有内容。这是我的分析输出 line_profiler :
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
2167 @profile
2168 def _removeFilterWidgetFromLayout(self, widget):
2169 """Remove filter widget"""
2170
2171 233 1528 6.6 1.0 self._collection_layout.removeWidget(widget)
2172 233 143998 618.0 97.9 widget.setParent(None)
2173 233 1307 5.6 0.9 widget.deleteLater()

使用 PyQt4 时,是否有一种“可接受”的方式来进行清理?我应该使用 setParent , deleteLater , 或两者?

最佳答案

了解实际情况的最简单方法可能是在交互式 session 中逐步完成:

>>> parent = QtGui.QWidget()
>>> child = QtGui.QWidget()
>>> layout = QtGui.QHBoxLayout(parent)
>>> layout.addWidget(child)
>>> child.parent() is layout
False
>>> child.parent() is parent
True

所以布局不会成为小部件的父级。这是有道理的,因为小部件只能有其他小部件作为父级,而布局不是小部件。添加到布局的所有小部件最终都会将其父级重置为布局的父级(只要它有一个)。
>>> item = layout.itemAt(0)
>>> item
<PyQt4.QtGui.QWidgetItem object at 0x7fa1715fe318>
>>> item.widget() is child
True

由于布局和它们包含的小部件之间没有父/子关系,因此需要不同的 API 来访问底层对象。项目归布局所有,但底层对象的所有权保持不变。
>>> layout.removeWidget(child)
>>> child.parent() is parent
True
>>> layout.count()
0
>>> repr(layout.itemAt(0))
'None'
>>> item
<PyQt4.QtGui.QWidgetItem object at 0x7fa1715fe318>

此时,布局已删除其项目(因为它拥有它的所有权),因此不再包含对包含的小部件的任何引用。鉴于此,使用 python 包装器为项目做很多事情不再安全(如果我们尝试调用它的任何方法,解释器可能会崩溃)。
>>> child.deleteLater()
>>> parent.children()
[<PyQt4.QtGui.QHBoxLayout object at 0x7fa1715fe1f8>]
>>> child.parent()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: wrapped C/C++ object of type QWidget has been deleted
>>>

由于我们仍然拥有子小部件的所有权,我们可以调用 deleteLater在上面。从回溯中可以看出,这将删除底层的 C++ 对象,但它的 python 包装器对象将被留下。但是,一旦任何剩余的对它的 python 引用消失,垃圾收集器将(最终)删除这个包装器。请注意,永远不需要调用 setParent(None)。在这个过程中。

最后一点:上面的解释器 session 有点误导,因为每次执行一行时都会处理事件队列。这意味着 deleteLater 的影响立即看到,如果代码作为脚本运行则不会出现这种情况。要在脚本中立即删除,您需要使用 sip模块:
>>> import sip
>>> sip.delete(child)

关于PyQt4 setParent vs deleteLater,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30241684/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com