QLayout.replace 不替换
Posted
技术标签:
【中文标题】QLayout.replace 不替换【英文标题】:QLayout.replace not replacing 【发布时间】:2020-07-25 22:30:15 【问题描述】:每次单击按钮 (self.btn
) 时,我都有以下代码来替换小部件 (self.lbl
):
import sys
from PySide2.QtCore import Slot
from PySide2.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, \
QPushButton
class Workshop(QWidget):
def __init__(self):
super().__init__()
self.n = 0
self.btn = QPushButton('Push me')
self.lbl = QLabel(str(self.n))
self.main_layout = QVBoxLayout()
self.sub_layout = QVBoxLayout()
self.sub_layout.addWidget(self.lbl)
self.sub_layout.addWidget(self.btn)
self.main_layout.addLayout(self.sub_layout)
self.btn.clicked.connect(self.change_label)
self.setLayout(self.main_layout)
self.show()
@Slot()
def change_label(self):
new_label = QLabel(str(self.n + 1))
self.main_layout.replaceWidget(self.lbl, new_label)
self.n += 1
self.lbl = new_label
if __name__ == '__main__':
app = QApplication()
w = Workshop()
sys.exit(app.exec_())
在初始化之后,对象w
看起来像这样:
当我点击“Push me”按钮 (self.btn
) 时,数字会根据需要递增,但初始的“0”仍保留在后台:
但是其他数字并没有保留在后台;只有“0”可以。例如,这里是“22”(我点击“Push me”22次后的结果):
注意: 我知道我可以使用 setText
方法实现我想要的结果,但这段代码只是我的一个 sn-p将适应一个我没有像setText
这样的方法的类。
谢谢!
【问题讨论】:
在self.main_layout.replaceWidget(self.lbl, new_label)
行之前添加行self.lbl.hide()
【参考方案1】:
当您替换布局中的小部件时,前一个小部件仍保留在那里。
来自replaceWidget()
:
widget from 的父级保持不变。
问题在于,当从布局中删除小部件时,它仍然保留其父级(在您的情况下,Workshop
实例),因此您仍然可以查看它。如果为您创建的每个新 QLabel 将对齐方式设置为 AlignCenter
,这一点会更清楚:您会看到,如果您添加一个新标签并调整窗口大小,前一个标签将保持其先前的位置:
class Workshop(QWidget):
def __init__(self):
# ...
self.lbl = QLabel(str(self.n), alignment=QtCore.Qt.AlignCenter)
# ...
def change_label(self):
new_label = QLabel(str(self.n + 1), alignment=QtCore.Qt.AlignCenter)
# ...
你有两种可能,实际上非常相似:
将“已移除”小部件的父级设置为None
:一旦您覆盖self.lbl
,垃圾收集器就会移除该小部件:
self.lbl.setParent(None)
通过调用 deleteLater()
来删除小部件,这是在将小部件重新设置为 None 时发生的情况,如果它没有其他持久引用,则会被垃圾收集:
self.lbl.deleteLater()
对于您的 pourposes,我建议您使用 deleteLater()
,因为调用 setParent()
(这是 QObject 的 setParent 的重新实现)实际上做了很多其他事情(最重要的是,检查焦点链并重置小部件的窗口标志),并且由于小部件无论如何都会被删除,所有这些实际上都是不必要的,并且无论如何都会调用 QObject 的 setParent(None)
实现。
您面临的图形“故障”可能取决于底层的低级绘画功能,在某些情况下,它在 MacOS 上会出现一些(已知的)意外行为。
【讨论】:
非常感谢@musicamante!您的回答在代码方面很有帮助,而且很有见地。我应该将self.lbl.deleteLater()
放在self.main_layout.replaceWidget(self.lbl, new_label)
之前还是之后?
顺便问一下,知道为什么这个错误只针对 0 而不是其他数字吗?
顺序没那么重要(因为deleteLater
,顾名思义,删除对象later),但我建议你把它放在after 替换布局中的小部件,只是为了逻辑和连贯性问题。如前所述,故障可能取决于MacOS下的那些错误,我不知道更多。以上是关于QLayout.replace 不替换的主要内容,如果未能解决你的问题,请参考以下文章