PyQt5 自我参考

Posted

技术标签:

【中文标题】PyQt5 自我参考【英文标题】:PyQt5 self reference 【发布时间】:2018-04-04 12:49:09 【问题描述】:

我使用 Qt Designer 设计了一个 GUI,并使用 PyQt5 中的命令将 .ui 文件转换为 .py。由此,我想在单击按钮时输出一个消息框。我已经在按钮监听器的功能上使用这行代码成功地完成了它:

QtWidgets.QMessageBox.about(MainWindow, "Result", "Invalid number entered!")

我在互联网上搜索过,但我不明白为什么这个不起作用。

QtWidgets.QMessageBox.about(self, "Result", "Invalid number entered!")

self 是否也指 MainWindow?

这里是完整的源代码。

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setWindowModality(QtCore.Qt.WindowModal)
        #MainWindow.resize(310, 185)
        MainWindow.setFixedSize(310, 185)
        MainWindow.setStyleSheet("#MainWindow\n"
    "\n"
    "    background-color:qradialgradient(spread:pad, cx:0.5, cy:0.5, 
    radius:1.696, fx:0.5, fy:0.505682, stop:0 rgba(0, 85, 255, 255), stop:1 
    rgba(255, 255, 255, 255))\n"
    "\n"
    "\n"
    "#firstNo_lineedit, #secondNo_lineedit\n"
    "\n"
    "    \n"
    "    background-color: rgb(28, 255, 123);\n"
    "\n"
    "\n"
    "")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.firstNo_lineedit = QtWidgets.QLineEdit(self.centralwidget)
        self.firstNo_lineedit.setGeometry(QtCore.QRect(130, 40, 113, 20))
        self.firstNo_lineedit.setObjectName("firstNo_lineedit")
        self.secondNo_lineedit = QtWidgets.QLineEdit(self.centralwidget)
        self.secondNo_lineedit.setGeometry(QtCore.QRect(130, 70, 113, 20))
        self.secondNo_lineedit.setObjectName("secondNo_lineedit")
        self.calculate_button = QtWidgets.QPushButton(self.centralwidget)
        self.calculate_button.setGeometry(QtCore.QRect(170, 100, 75, 23))
        self.calculate_button.setObjectName("calculate_button")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(60, 40, 81, 20))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(60, 70, 61, 20))
        self.label_2.setObjectName("label_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 310, 21))
        self.menubar.setObjectName("menubar")
        self.menuAbout = QtWidgets.QMenu(self.menubar)
        self.menuAbout.setObjectName("menuAbout")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menuAbout.menuAction())

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

        # ================= Listeners ===================
        self.calculate_button.clicked.connect(self.basicArithmetic)
        # ============================================

    # ================= Events ===================
    def basicArithmetic(self):
        try:
            firstNo=float(self.firstNo_lineedit.text())
            secondNo=float(self.secondNo_lineedit.text())

            resSum=firstNo+secondNo
            resDiff=firstNo-secondNo
            resMul=firstNo*secondNo
            resDiv=round(firstNo/secondNo,2)

            print("Sum: ".format(resSum))
            print("Difference: ".format(resDiff))
            print("Product: ".format(resMul))
            print("Quotient: ".format(resDiv))

            toDisplay="Sum: ".format(resSum)
            toDisplay+="\n"
            toDisplay+="Difference: ".format(resDiff)
            toDisplay+="\n"
            toDisplay+="Product: ".format(resMul)
            toDisplay+="\n"
            toDisplay+="Quotient: ".format(resDiv)

            #QtWidgets.QMessageBox.about(self, "Result", toDisplay)
            QtWidgets.QMessageBox.about(MainWindow, "Result", toDisplay)

        except ValueError:
            #QtWidgets.QMessageBox.about(self, "Result", toDisplay)
            QtWidgets.QMessageBox.about(MainWindow, "Result", "Invalid number entered!")
    # ============================================

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.calculate_button.setText(_translate("MainWindow", "Calculate"))
        self.label.setText(_translate("MainWindow", "First No.:"))
        self.label_2.setText(_translate("MainWindow", "Second No.:"))
        self.menuAbout.setTitle(_translate("MainWindow", "About"))
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_())

【问题讨论】:

【参考方案1】:

self 是引用相同实例的类的方法的第一个参数(名称是约定俗成的,不是强制性的)。

对于另一个QMessageBox.about() 需要一个从QWidget 或None 继承的某种对象作为第一个参数。

如果我们查看 Qt Designer 生成的类,我们清楚地看到它不是一个小部件,实际上该类的唯一目的是作为一个接口来填充另一个小部件:

MainWindow = QtWidgets.QMainWindow() # create widget
ui = Ui_MainWindow() # create interface
ui.setupUi(MainWindow) # fill widget

因此,您要传递的selfUi_MainWindow 的实例是不合适的,因为它不引用小部件,但MainWindow 是一个小部件,因此它可以在该更改下正常工作。 同样在生成的文件中,您会看到以下消息:

# WARNING! All changes made in this file will be lost!

该消息是因为如果您想更改设计,您将不得不覆盖您编写的逻辑,例如您的 basicArithmetic 方法,这会使项目无法维持。

PyQt 我建议创建另一个使用生成 QtDesigner 的类的类,我假设生成的文件名为 design.py

design.py:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'design.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setWindowModality(QtCore.Qt.WindowModal)
        #MainWindow.resize(310, 185)
        MainWindow.setFixedSize(310, 185)
        MainWindow.setStyleSheet("#MainWindow\n"
    "\n"
    "    background-color:qradialgradient(spread:pad, cx:0.5, cy:0.5," 
    "radius:1.696, fx:0.5, fy:0.505682, stop:0 rgba(0, 85, 255, 255), stop:1" 
    "rgba(255, 255, 255, 255))\n"
    "\n"
    "\n"
    "#firstNo_lineedit, #secondNo_lineedit\n"
    "\n"
    "    \n"
    "    background-color: rgb(28, 255, 123);\n"
    "\n"
    "\n"
    "")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.firstNo_lineedit = QtWidgets.QLineEdit(self.centralwidget)
        self.firstNo_lineedit.setGeometry(QtCore.QRect(130, 40, 113, 20))
        self.firstNo_lineedit.setObjectName("firstNo_lineedit")
        self.secondNo_lineedit = QtWidgets.QLineEdit(self.centralwidget)
        self.secondNo_lineedit.setGeometry(QtCore.QRect(130, 70, 113, 20))
        self.secondNo_lineedit.setObjectName("secondNo_lineedit")
        self.calculate_button = QtWidgets.QPushButton(self.centralwidget)
        self.calculate_button.setGeometry(QtCore.QRect(170, 100, 75, 23))
        self.calculate_button.setObjectName("calculate_button")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(60, 40, 81, 20))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(60, 70, 61, 20))
        self.label_2.setObjectName("label_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 310, 21))
        self.menubar.setObjectName("menubar")
        self.menuAbout = QtWidgets.QMenu(self.menubar)
        self.menuAbout.setObjectName("menuAbout")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menuAbout.menuAction())

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.calculate_button.setText(_translate("MainWindow", "Calculate"))
        self.label.setText(_translate("MainWindow", "First No.:"))
        self.label_2.setText(_translate("MainWindow", "Second No.:"))
        self.menuAbout.setTitle(_translate("MainWindow", "About"))

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_())

这个新类可以有以下形式:

ma​​in.py:

from PyQt5 import QtCore, QtGui, QtWidgets

from design import Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
        self.setupUi(self)  

        # ================= Listeners ===================
        self.calculate_button.clicked.connect(self.basicArithmetic)
        # ============================================

    # ================= Events ===================
    def basicArithmetic(self):
        try:
            firstNo=float(self.firstNo_lineedit.text())
            secondNo=float(self.secondNo_lineedit.text())

            resSum=firstNo+secondNo
            resDiff=firstNo-secondNo
            resMul=firstNo*secondNo
            resDiv=round(firstNo/secondNo,2)

            print("Sum: ".format(resSum))
            print("Difference: ".format(resDiff))
            print("Product: ".format(resMul))
            print("Quotient: ".format(resDiv))

            toDisplay="Sum: ".format(resSum)
            toDisplay+="\n"
            toDisplay+="Difference: ".format(resDiff)
            toDisplay+="\n"
            toDisplay+="Product: ".format(resMul)
            toDisplay+="\n"
            toDisplay+="Quotient: ".format(resDiv)

            #QtWidgets.QMessageBox.about(self, "Result", toDisplay)
            QtWidgets.QMessageBox.about(self, "Result", toDisplay)

        except ValueError:
            #QtWidgets.QMessageBox.about(self, "Result", toDisplay)
            QtWidgets.QMessageBox.about(self, "Result", "Invalid number entered!")

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

这就是为什么在许多情况下,self 被视为第一个参数。

您可以在以下链接中找到更多信息:

http://pyqt.sourceforge.net/Docs/PyQt5/designer.html

【讨论】:

谢谢!我仍然需要在 OOP 中打下基础。最后一个问题,当Python中的一个类中涉及一个参数时,这意味着什么。例如,像这样:class MainWindow(QMainWindow): @LinkedRom 这就是所谓的继承,就像你继承你父母的特性一样,MainWindow类继承自QMainWindow,所以它有它所有的方法和属性,可以让你创建一个自定义窗口,就像你是你父母的定制版。 :D。这是 OOP 的最佳属性之一,它使我们免于编写成千上万行代码。【参考方案2】:

没有自我指的是Ui_MainWindowclass,其中MainWindow指的是QtWidgets.QMainWindow() 因此,当您说QtWidgets.QMessageBox.about(self, "Result", toDisplay) 时,它会将Ui_MainWindow 视为父母QWidget,这是不正确的。

这次当您调用QtWidgets.QMessageBox.about(MainWindow, "Result", toDisplay) 时,您的代码将运行良好,因为MainWindow 是有效的QWidget,即QtWidgets.QMainWindow()

希望这会有所帮助。

【讨论】:

以上是关于PyQt5 自我参考的主要内容,如果未能解决你的问题,请参考以下文章

英文自我介绍

语音英文自我介绍

英文简短的自我介绍

web前端的自我介绍

前端面试怎么自我介绍

大学生前端面试自我介绍