简体   繁体   中英

PyQt5 self reference

I used Qt Designer to design a GUI and use the command in PyQt5 to convert the .ui file to .py. From that, I want to output a messagebox when a button is clicked. I have successfully done it using this line of code on the function of the button listener:

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

I have searched around the internet but I don't understand why this one don't work.

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

Does the self their refer to the MainWindow also?

Here is the full source code.

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

self is the first parameter of the methods (the name is by convention, is not mandatory) of a class that refers to the instance of the same.

For another QMessageBox.about() requires as first parameter an object of some kind that inherits from QWidget or also None.

If we review the class generated by Qt Designer, we clearly see that it is not a widget, in fact the only objective of that class is to be an interface to fill in another widget:

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

Therefore the self , the instance of Ui_MainWindow , you want to pass is not appropriate because it does not refer to the widget, but the MainWindow is a widget, so it works correctly with that change. Also within the generated file you have the following message:

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

That message is because if you want to change the design you will have to overwrite the logic that you wrote, such as your basicArithmetic method, which makes the project untenable.

PyQt I recommend to create another class that uses the class that generates QtDesigner, I assume that the generated file is called 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_())

This new class can have the following form:

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

And that is the reason why, in many cases, self is seen as the first parameter.

You can find more information at the following link:

No self refers to Ui_MainWindow class where MainWindow reffers to QtWidgets.QMainWindow() So when you say QtWidgets.QMessageBox.about(self, "Result", toDisplay) it will treat Ui_MainWindow as a parent QWidget which is not correct.

when you call QtWidgets.QMessageBox.about(MainWindow, "Result", toDisplay) this time your code will run fine because MainWindow is a valid QWidget ie QtWidgets.QMainWindow()

hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM