PyQt 更新子控件 属性

PyQt Update Child Widget Property

我想更新主 window 中另一个 window 中的 TextBrowser 小部件。目标是简单地将字符串写入小部件以充当伪控制台。当我检查 QTextBrowser 对象时,我可以看到它支持 setText() - 但我找不到从主 window 对象访问 setText() 的方法(我怀疑是因为我'没有正确调用它)。不需要使用 TextBrowser 小部件。

我看到的示例讨论了使用信号和槽进行此类操作,但对于我要实现的目标来说,这似乎有点过头了。是否需要为如此简单的事情使用信号,或者我可以从主要 window 以某种方式 setText()(或类似的东西)?

scratch.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from PyQt5 import QtWidgets
import sys

from log_dialog import Ui_dialog

class Application(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(Application, self).__init__(*args, **kwargs)

        self.show()

        # ===================================================
        self.log_widget = QtWidgets.QDialog()
        ui = Ui_dialog()
        ui.setupUi(self.log_widget)
        self.log_widget.exec_()

        # Write some text to log_widget  <-----

        # ===================================================

qApp = QtWidgets.QApplication(sys.argv)
application_window = Application()
sys.exit(qApp.exec_())

log_dialog.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'log_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.3
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_dialog(object):
    def setupUi(self, dialog):
        dialog.setObjectName("dialog")
        dialog.resize(398, 307)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(dialog.sizePolicy().hasHeightForWidth())
        dialog.setSizePolicy(sizePolicy)
        self.textBrowser = QtWidgets.QTextBrowser(dialog)
        self.textBrowser.setGeometry(QtCore.QRect(9, 9, 381, 291))
        self.textBrowser.setObjectName("textBrowser")

        self.retranslateUi(dialog)
        QtCore.QMetaObject.connectSlotsByName(dialog)

    def retranslateUi(self, dialog):
        _translate = QtCore.QCoreApplication.translate
        dialog.setWindowTitle(_translate("dialog", "Log"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    dialog = QtWidgets.QDialog()
    ui = Ui_dialog()
    ui.setupUi(dialog)
    dialog.show()
    sys.exit(app.exec_())

“表单 class”(Ui_dialog)创建的所有对象都是该表单 class 实例的成员。

如果您查看 setupUi() 代码,您会发现所有小部件都是作为 Ui_dialog class 实例(self.textBrowser 等)的成员创建的.
由于 ui 是实例,因此 self.someObject 可作为 ui.someObject.

访问
    ui = Ui_dialog()
    ui.setupUi(self.log_widget)
    ui.textBrowser.setText('Hello there!')
    self.log_widget.exec_()

对于非常简单的情况,这可能没问题,但是使用 ui“形式 class”作为独立对象通常不是很方便,特别是如果您没有创建持久引用到ui:在你的情况下,一旦主windowreturns的__init__(当对话框关闭时),你将没有更多的参考到 ui,因为它只是一个仅存在于 __init__.
范围内的未引用变量 尽管如此,您仍然可以访问该对话框并再次执行它,访问其任何子项的唯一方法是通过:

self.log_widget.findChild(QtWidgets.QTextBrowser, 'textBrowser')

不太方便吧?

一种可能性是使 ui 成为对话实例的成员:

    self.log_widget.ui = Ui_dialog()
    self.log_widget.ui.setupUi(self.log_widget)
    self.log_widget.ui.textBrowser.setText('Hello there!')

更好,但不是很好:它只有 3 个字符,但它确实没有提供很多好处。此外,拥有 self.log_widget 的直接子对象但只能通过 self.log_widget.ui.

访问的对象确实没有多大意义

更常见和推荐的方法是多重继承方法,它允许始终直接访问对象。唯一的缺点是,即使对于简单的小部件和对话框,您总是需要创建子class。

class LogWidget(QtWidgets.QDialog, Ui_dialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)


class Application(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(Application, self).__init__(*args, **kwargs)
        # ...

        self.log_widget = LogWidget()
        self.log_widget.textBrowser.setText('hello there!')
        self.log_widget.exec_()

如您所见,它的工作方式几乎相同,只是它更简单、简洁和可读。