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
因此,您要传递的self
,Ui_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_())
这个新类可以有以下形式:
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_())
这就是为什么在许多情况下,self
被视为第一个参数。
您可以在以下链接中找到更多信息:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html【讨论】:
谢谢!我仍然需要在 OOP 中打下基础。最后一个问题,当Python中的一个类中涉及一个参数时,这意味着什么。例如,像这样:class MainWindow(QMainWindow):
@LinkedRom 这就是所谓的继承,就像你继承你父母的特性一样,MainWindow类继承自QMainWindow,所以它有它所有的方法和属性,可以让你创建一个自定义窗口,就像你是你父母的定制版。 :D。这是 OOP 的最佳属性之一,它使我们免于编写成千上万行代码。【参考方案2】:
没有自我指的是Ui_MainWindow
class,其中MainWindow
指的是QtWidgets.QMainWindow()
因此,当您说QtWidgets.QMessageBox.about(self, "Result", toDisplay)
时,它会将Ui_MainWindow
视为父母QWidget
,这是不正确的。
这次当您调用QtWidgets.QMessageBox.about(MainWindow, "Result", toDisplay)
时,您的代码将运行良好,因为MainWindow
是有效的QWidget
,即QtWidgets.QMainWindow()
希望这会有所帮助。
【讨论】:
以上是关于PyQt5 自我参考的主要内容,如果未能解决你的问题,请参考以下文章