PyQt:重新创建小部件

Posted

技术标签:

【中文标题】PyQt:重新创建小部件【英文标题】:PyQt: Recreating widgets 【发布时间】:2014-04-12 15:29:41 【问题描述】:

我有一个需要重新创建的小部件。我在下面做了一个大大简化的例子。在示例中,我想使用新属性重新创建小部件。我知道在这个例子中我可以使用QtGui.QLabel.setText(),但是我不能在真正的程序中做同样的事情。

示例如下:

from PyQt4 import QtGui
import sys

class MainWindow(QtGui.QWidget):
    def __init__(self):
        super().__init__()
        self.initAttributes()
        self.initLabel()
        self.initUI()

    def initAttributes(self):
        self.text = 'initial text'

    def initLabel(self):
        self.label = QtGui.QLabel()
        self.label.setText(self.text)

    def changeText(self):
        self.text = 'different text'
        self.initLabel()
        self.initUI()

    def initUI(self):
        button = QtGui.QPushButton()
        button.clicked.connect(self.changeText)
        grid = QtGui.QGridLayout()
        grid.addWidget(self.label)
        grid.addWidget(button)
        self.setLayout(grid)
        self.show()


app = QtGui.QApplication(sys.argv)
window = MainWindow()
app.exec_()

我在这里要做的是制作一个具有一些初始属性的小部件,在本例中是一个带有文本'initial text' 的标签。如前所述,我并没有尝试更改属性,而是尝试使用从属于窗口对象的属性中获取的新属性来重新创建对象。

按钮背后的想法是,当按下时,它会将窗口的'self.text'属性更改为其他内容,并尝试使用与以前相同的方法重新创建标签, initLabel.

结果应该是窗口被重新初始化,重新创建的标签将有新的文本'different text'。但是,什么也没有发生。

编辑: 解决方案是不能为同一个小部件调用两次setLayout。在 Schollii 的链接答案中使用小部件重置技术时,它可以正常工作。以下是修改后的工作函数(而不是再次转储整个代码)

def changeText(self):
    self.text = 'different text'
    self.initLabel()
    self.delLayout()
    self.initUI()

def delLayout(self):
    QtGui.QWidget().setLayout(self.layout())

【问题讨论】:

您能展示一下您是如何尝试重新创建它的吗?这样做有什么问题? 如果您查看代码,您会看到连接到按钮的函数调用了 initLabel 函数,该函数应该将 self.label 设置为空白 QLabel。如果你执行代码并按下按钮,什么都不会发生 预期结果应该是使用文本“不同文本”创建标签,因为这是调用 initLabel 时 self.text 的值 我看到您正在重新创建小部件中的所有内容,这是重新创建标签的要求还是要求,但您重新创建了其余部分以便您可以看到新标签? 是的,实际程序中的所有其他小部件都需要完全重新初始化 【参考方案1】:

在您的代码中,当您单击按钮时,您正在执行等效操作:

def changeText(self):
    self.text = 'different text'
    self.label = QtGui.QLabel(self.text)
    self.initUI()

这会创建新标签并重新初始化 UI(重复信号连接、创建小部件、设置布局等)。

如果您想重新创建标签而不是设置其文本,则不应重新初始化 UI。相反,您应该只从布局中删除您重新创建的项目并重新添加它们。示例:

self.layout().removeWidget(self.label)
self.text = 'new text'
self.label = QtGui.QLabel(self.text)
self.layout().addWidget(self.label, 0, 0)

如果您想重新创建整个小部件,您应该清除其所有布局的项目,或者用新的空布局替换布局,如这篇 SO 帖子 replacing layout on a QWidget with another layout 中所述(您不能多次调用 setLayout(),但是你可以转移布局!)。

【讨论】:

如果我使用链接帖子中显示的删除布局的方法,那么 UI 可以重新初始化并且它应该可以正常工作,three_pinapple 的答案是它不工作的原因 @CharlieSeymour 是的,我同意,但不幸的是布局替换是不正确的。无论如何,希望有人觉得我的回答很有用:) 欢迎来到 SO! 再详细看一下,我发现您实际上是对的,我已将您的帖子更正为答案!感谢您的帮助!【参考方案2】:

您的示例失败,因为您无法设置 QMainWindow 的布局(如果它已经有一个)。 如果您在终端可见的情况下运行示例代码,您会在单击按钮时看到以下错误消息。

QWidget::setLayout: 试图在已经有布局的主窗口“”上设置 QLayout“”

理论上,您应该能够删除旧布局并添加新布局,但这在 PyQt 中似乎很困难。 (编辑:有关如何删除和重新添加布局,请参阅 Schollii 的回答)

我建议您查看您是否真的需要重新创建整个布局,或者您是否只需要替换布局中的小部件。如果您选择后者,有很多关于删除/替换布局中的小部件的 *** 帖子。

【讨论】:

啊,谢谢你,我不知道你不能在 windows 上重置布局 @CharlieSeymour 这不是真的你可以看到我的回答

以上是关于PyQt:重新创建小部件的主要内容,如果未能解决你的问题,请参考以下文章

使用 QtDesigner PyQt4 创建自定义小部件

PyQt5 制作子类小部件

控制 PyQt QFormLayout 中的小部件放置

如何使用 PyQt 在小部件上绘制点和线

PyQt 小部件 connect() 和 disconnect()

如何防止 PyQt 小部件被掩盖?