在子类对话框 window 中使用方法影响主要 window 的问题

Problems using method in subclass dialog window to affect main window

我正在尝试使用 PyQT5 创建一个 GUI 程序。我是编程新手,Python 所以如果我以错误的方式解释事情,请纠正我。

我有一个主 window,它将包含多个 QLineEdit 小部件和相应的 "Clear" 按钮以清除用户输入的数据。主 window 还包含 "Edit" 按钮,用于显示特定的对话框,也可以在其中编辑数据。我的示例有一个 "User ID" QLineEdit widget/text 框,"Clear" 和 "Edit" 按钮。

单击“编辑”时出现的对话框有自己的 "Clear" 按钮。如果单击对话框中的清除按钮 window,对话框中的 QLineEdit 小部件和主要window 应该清除。

问题:当我从对话框windowclass继承主要class方法时,clearUserID()用于清除User ID 字段调用失败。

当我不继承主要 window class clearUserID 方法时,我可以清除对话框 QLineEdit (UserIDWin_UserID_lnedt) 但不能 主要 window (UserID_lnedt) 上的相应小部件。我尝试使用对话框 "Clear" 按钮清除主要 window QLineEdit 小部件的所有代码导致我的程序崩溃。

有人可以帮助我更好地理解这些原则背后的逻辑以及如何让我的代码正常工作吗?谢谢。

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(820, 611)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(0, 0, 801, 551))
        self.tabWidget.setObjectName("tabWidget")
        self.MainTab = QtWidgets.QWidget()
        self.MainTab.setObjectName("MainTab")
        self.UserID_Edit_pb = QtWidgets.QPushButton(self.MainTab)
        self.UserID_Edit_pb.setGeometry(QtCore.QRect(210, 10, 31, 23))
        self.UserID_Edit_pb.setObjectName("UserID_Edit_pb")
        self.UserID_Edit_pb.clicked.connect(self.openUserIDWin)
        self.UserID_Clear_pb_2 = QtWidgets.QPushButton(self.MainTab)
        self.UserID_Clear_pb_2.setGeometry(QtCore.QRect(170, 9, 41, 23))
        self.UserID_Clear_pb_2.setObjectName("UserID_Clear_pb_2")
        self.UserID_le = QtWidgets.QLineEdit(self.MainTab)
        self.label = QtWidgets.QLabel(self.MainTab)
        self.label.setGeometry(QtCore.QRect(10, 10, 47, 13))
        self.UserID_le.setGeometry(QtCore.QRect(50, 10, 113, 20))
        self.UserID_le.setObjectName("UserID_le")
        self.tabWidget.addTab(self.MainTab, "")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 820, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.UserID_Clear_pb_2.clicked.connect(self.UserID_le.clear)


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.UserID_Edit_pb.setText(_translate("MainWindow", "Edit"))
        self.UserID_Clear_pb_2.setText(_translate("MainWindow", "Clear"))
        self.label.setText(_translate("MainWindow", "User ID"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.MainTab), _translate("MainWindow", "Tab"))

    def openUserIDWin(self):
        UserID_value = self.UserID_le.text()
        UserIDWin = QtWidgets.QDialog()
        ui = Ui_UserIDWin(UserID_value)
        ui.setupUi(UserIDWin)
        UserIDWin.exec_();



class Ui_UserIDWin(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, userID):
        print("The User ID is:" + userID)
        self.userID = userID

    def setupUi(self, UserIDWin):
        UserIDWin.setObjectName("UserIDWin")
        UserIDWin.resize(400, 124)
        self.UserIDWin_UserID_lnedt = QtWidgets.QLineEdit(UserIDWin)
        self.UserIDWin_UserID_lnedt.setText(self.userID)
        self.UserIDWin_UserID_lnedt.setGeometry(QtCore.QRect(20, 50, 113, 20))
        self.UserIDWin_UserID_lnedt.setObjectName("UserIDWin_UserID_lnedt")
        self.UserIDWin_UserID_lbl = QtWidgets.QLabel(UserIDWin)
        self.UserIDWin_UserID_lbl.setGeometry(QtCore.QRect(20, 30, 47, 13))
        self.UserIDWin_UserID_lbl.setObjectName("UserIDWin_UserID_lbl")
        self.UserIDWin_UserIDClear_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_UserIDClear_pushb.setGeometry(QtCore.QRect(140, 50, 41, 23))
        self.UserIDWin_UserIDClear_pushb.setObjectName("UserIDWin_UserIDClear_pushb")
        self.UserIDWin_Cancel_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_Cancel_pushb.setGeometry(QtCore.QRect(110, 80, 75, 23))
        self.UserIDWin_Cancel_pushb.setObjectName("UserIDWin_Cancel_pushb")
        self.UserIDWin_Next_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_Next_pushb.setGeometry(QtCore.QRect(190, 80, 75, 23))
        self.UserIDWin_Next_pushb.setObjectName("UserIDWin_Next_pushb")

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

        #If I do not inherit from "QtWidgets.QMainWindow, Ui_MainWindow" the code below works and invokes clearUserId().  However, I then am having problems using SetText on the main window UserId_le text box and the program crashes.
        self.UserIDWin_UserIDClear_pushb.clicked.connect(self.clearUserID)

    def retranslateUi(self, UserIDWin):
        _translate = QtCore.QCoreApplication.translate
        UserIDWin.setWindowTitle(_translate("UserIDWin", "Dialog"))
        self.UserIDWin_UserID_lbl.setText(_translate("UserIDWin", "User ID"))
        self.UserIDWin_UserIDClear_pushb.setText(_translate("UserIDWin", "Clear"))
        self.UserIDWin_Cancel_pushb.setText(_translate("UserIDWin", "Cancel"))
        self.UserIDWin_Next_pushb.setText(_translate("UserIDWin", "Next"))

    def clearUserID(self):
        self.UserIDWin_UserID_lnedt.setText('')
        # The line below crashes my program if I am able to invoke this method.
        #self.Ui_MainWindow.UserID_le.setText('')

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

似乎他们对继承和良好实践有一定清晰的概念,但其他人不喜欢以下内容:

  • PyQt 建议不要修改 Qt Designer 生成的代码,因为您将来可能想要修改 GUI,并且在使用 pyuic 时会覆盖初始代码。另一个问题是初学者不理解Qt Designer生成的class不是一个widget而是一个接口,用来填充另一个widget,因此除了其他问题之外不能覆盖widget的方法。

  • 你只需要从另一个class的对象修改一个class的对象,如果两者具有相同的范围,在你想要清理QLineEdit的情况下从另一个 window 中分离主 window 是一项危险的任务,相反,您应该执行该逻辑,其中两个 windows 具有相同的范围并且在 openUserIDWin 方法中。

  • QLineEdit已经有clear()方法允许清除,它实现与setText("")相同的功能,但第一种方法更具可读性。

综合以上,解决方案是:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(820, 611)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(0, 0, 801, 551))
        self.tabWidget.setObjectName("tabWidget")
        self.MainTab = QtWidgets.QWidget()
        self.MainTab.setObjectName("MainTab")
        self.UserID_Edit_pb = QtWidgets.QPushButton(self.MainTab)
        self.UserID_Edit_pb.setGeometry(QtCore.QRect(210, 10, 31, 23))
        self.UserID_Edit_pb.setObjectName("UserID_Edit_pb")
        self.UserID_Clear_pb_2 = QtWidgets.QPushButton(self.MainTab)
        self.UserID_Clear_pb_2.setGeometry(QtCore.QRect(170, 9, 41, 23))
        self.UserID_Clear_pb_2.setObjectName("UserID_Clear_pb_2")
        self.UserID_le = QtWidgets.QLineEdit(self.MainTab)
        self.label = QtWidgets.QLabel(self.MainTab)
        self.label.setGeometry(QtCore.QRect(10, 10, 47, 13))
        self.UserID_le.setGeometry(QtCore.QRect(50, 10, 113, 20))
        self.UserID_le.setObjectName("UserID_le")
        self.tabWidget.addTab(self.MainTab, "")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 820, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.UserID_Edit_pb.setText(_translate("MainWindow", "Edit"))
        self.UserID_Clear_pb_2.setText(_translate("MainWindow", "Clear"))
        self.label.setText(_translate("MainWindow", "User ID"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.MainTab), _translate("MainWindow", "Tab"))


class Ui_UserIDWin(object):
    def setupUi(self, UserIDWin):
        UserIDWin.setObjectName("UserIDWin")
        UserIDWin.resize(400, 124)
        self.UserIDWin_UserID_lnedt = QtWidgets.QLineEdit(UserIDWin)
        self.UserIDWin_UserID_lnedt.setGeometry(QtCore.QRect(20, 50, 113, 20))
        self.UserIDWin_UserID_lnedt.setObjectName("UserIDWin_UserID_lnedt")
        self.UserIDWin_UserID_lbl = QtWidgets.QLabel(UserIDWin)
        self.UserIDWin_UserID_lbl.setGeometry(QtCore.QRect(20, 30, 47, 13))
        self.UserIDWin_UserID_lbl.setObjectName("UserIDWin_UserID_lbl")
        self.UserIDWin_UserIDClear_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_UserIDClear_pushb.setGeometry(QtCore.QRect(140, 50, 41, 23))
        self.UserIDWin_UserIDClear_pushb.setObjectName("UserIDWin_UserIDClear_pushb")
        self.UserIDWin_Cancel_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_Cancel_pushb.setGeometry(QtCore.QRect(110, 80, 75, 23))
        self.UserIDWin_Cancel_pushb.setObjectName("UserIDWin_Cancel_pushb")
        self.UserIDWin_Next_pushb = QtWidgets.QPushButton(UserIDWin)
        self.UserIDWin_Next_pushb.setGeometry(QtCore.QRect(190, 80, 75, 23))
        self.UserIDWin_Next_pushb.setObjectName("UserIDWin_Next_pushb")

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

    def retranslateUi(self, UserIDWin):
        _translate = QtCore.QCoreApplication.translate
        UserIDWin.setWindowTitle(_translate("UserIDWin", "Dialog"))
        self.UserIDWin_UserID_lbl.setText(_translate("UserIDWin", "User ID"))
        self.UserIDWin_UserIDClear_pushb.setText(_translate("UserIDWin", "Clear"))
        self.UserIDWin_Cancel_pushb.setText(_translate("UserIDWin", "Cancel"))
        self.UserIDWin_Next_pushb.setText(_translate("UserIDWin", "Next"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.UserID_Edit_pb.clicked.connect(self.openUserIDWin)
        self.UserID_Clear_pb_2.clicked.connect(self.UserID_le.clear)

    def openUserIDWin(self):
        UserID_value = self.UserID_le.text()
        w = UserIDWin(UserID_value)
        w.UserIDWin_UserIDClear_pushb.clicked.connect(self.UserID_le.clear)
        w.exec_()


class UserIDWin(QtWidgets.QDialog, Ui_UserIDWin):
    def __init__(self, userID, parent=None):
        super(UserIDWin, self).__init__(parent)
        self.setupUi(self)
        self.userID = userID
        self.UserIDWin_UserID_lnedt.setText(self.userID)
        self.UserIDWin_UserIDClear_pushb.clicked.connect(self.UserIDWin_UserID_lnedt.clear)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

我推荐你阅读: