TL;博士
不要覆盖self.ui。
解释
uic 组合的工作原理
常用的方法之一适当地使用 pyuic 生成的文件是使用组合(而不是多重继承):
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
from ui_mainWindow import Ui_MainWindow
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.myLineEdit.setText('some text')
这很好,也很有意义:概念是创建 pyuic 类(有时称为“表单类”)的实例,然后使用该实例“设置”实际窗口,self.ui 对象包含对所有小部件的引用。
请注意,使 ui 持久化(使用实例属性)实际上并不是一个严格的要求,但为了能够直接访问小部件通常是必需的,这对于创建信号连接或读取属性通常很重要。
但是,如果这不是必需的,它仍然可以工作:小部件会自动“重新定位”到主窗口(或其直接父窗口),并且垃圾收集不是问题,因为 Qt 会在内部保留自己的引用(在 Qt 术语中) , "窗口占用所有权”)。
从技术上讲,这是完全有效的:
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
Ui_MainWindow().setupUi(self)
然后,我们仍然可以使用findChild 及其对象名称(在 Designer 中设置)访问小部件:
self.findChild(QLineEdit, 'myLineEdit').setText('some text')
显然,它不是很实用。
创建“子”窗口
当需要创建子窗口(通常是对话框)时,通常建议使用实例属性来避免垃圾收集:
def createWindow(self):
self.window = QDialog()
self.window.show()
如果该对话框也有一个 Designer 文件,我们需要做一些类似于开始时所做的事情。不幸的是,一个非常常见的错误是使用相同的名称创建 ui 实例:
def createWindow(self):
self.window = QDialog()
self.ui = Ui_Dialog()
self.ui.setupUi(self.window)
self.ui.anotherLineEdit.setText('another text')
self.window.show()
这是理论上很好:一切都按预期工作。但是有一个很大的问题:上面覆盖self.ui,意思是我们输了全部对主窗口小部件的引用。
假设您要根据主窗口中写入的文本来设置对话框中行编辑的文本;以下可能会崩溃:
def createWindow(self):
self.window = QDialog()
self.ui = Ui_Dialog()
self.ui.setupUi(self.window)
self.ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
self.window.show()
这清楚地表明了一个重要方面:必须始终思考在分配可能已经存在的属性之前。
在上面的代码中,这实际上已经完成两次:我们不仅覆盖了我们之前创建的self.ui,而且我们还为window()做了它,这是一个现有的函数全部Qt 小部件(它返回调用它的小部件的顶级祖先窗口)。
根据经验,总是花时间决定如何命名对象,使用聪明的名称,并考虑最常见的名称可能已经被采用:记住检查您正在使用的小部件类型的文档中的“所有成员列表,包括继承的成员”链接,直到您有足够的经验来记住它们。
解决方案
显而易见的解决方案是为对话框的 ui 使用不同的名称:
def createWindow(self):
self.dialog = QDialog()
self.dialog_ui = Ui_Dialog()
self.dialog_ui.setupUi(self.dialog)
self.dialog_ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
self.dialog.show()
一个更好的解决方案是为您的对话框创建一个子类:
class MyDialog(QDialog):
def __init__(self, parent=None)
super().__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
class MyWindow(QMainWindow):
# ...
def createWindow(self):
self.dialog = MyDialog()
self.dialog.ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
self.dialog.show()
还要记住,另一种常见的(根据我的经验,更简单、更直观)的方法是使用多重继承而不是组合:
class MyDialog(QDialog, Ui_Dialog):
def __init__(self, parent=None)
super().__init__(parent)
self.setupUi(self)
class MyWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.myLineEdit.setText('some text')
def createWindow(self):
self.dialog = MyDialog()
self.dialog.anotherLineEdit.setText(self.myLineEdit.text())
self.dialog.show()
这种方法的唯一问题是它可能会无意中覆盖“主”小部件的功能名称:例如,如果您在 Designer 中创建了一个子小部件并将其重命名为“窗口”。如上所述,如果您总是仔细考虑分配给对象的名称,这可能永远不会发生(将小部件命名为“窗口”没有多大意义)。