目录

一. 使用designer.exe设计UI

二. 使用pyuic5.exe将ui文件转为py文件

三. 主程序设计

1. 最小主程序设计,不响应button事件

2. 加入代码,响应button事件(由Qt的信号和槽实现)

3. 计算器的详细实现代码如下

四. 测试

五. 小结


在之前的博客中,介绍了 PyQt5环境搭建,今天使用PyQt5制作一个简单的计算器。

下面开始正文。

一. 使用designer.exe设计UI

打开designer.exe, 选择 “文件(F)” -> "新建(N)", 选择模板“Widget”然后点击创建。

UI中使用了QLineEdit、QGridLayout和QPushButton,其中button是放在GridLayout中摆放,详细设计如下图;设计完成后,保存为“CalUi.ui”文件。

二. 使用pyuic5.exe将ui文件转为py文件

使用如下命令将ui文件转为py文件。

pyuic5.exe -o CalUi.py CalUi.ui

转换后的CalUi.py文件如下,

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

# Form implementation generated from reading ui file 'CalUi.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(600, 400)
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setGeometry(QtCore.QRect(130, 60, 331, 40))
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.lineEdit.setFont(font)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayoutWidget = QtWidgets.QWidget(Form)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(130, 120, 326, 221))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(4, 4, 4, 4)
        self.gridLayout.setHorizontalSpacing(6)
        self.gridLayout.setObjectName("gridLayout")
        self.btn_equal = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_equal.setFont(font)
        self.btn_equal.setObjectName("btn_equal")
        self.gridLayout.addWidget(self.btn_equal, 4, 2, 1, 1)
        self.btn_4 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_4.setFont(font)
        self.btn_4.setObjectName("btn_4")
        self.gridLayout.addWidget(self.btn_4, 2, 0, 1, 1)
        self.btn_7 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_7.setFont(font)
        self.btn_7.setObjectName("btn_7")
        self.gridLayout.addWidget(self.btn_7, 3, 0, 1, 1)
        self.btn_1 = QtWidgets.QPushButton(self.gridLayoutWidget)
        self.btn_1.setEnabled(True)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_1.setFont(font)
        self.btn_1.setCheckable(False)
        self.btn_1.setObjectName("btn_1")
        self.gridLayout.addWidget(self.btn_1, 0, 0, 1, 1)
        self.btn_9 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_9.setFont(font)
        self.btn_9.setObjectName("btn_9")
        self.gridLayout.addWidget(self.btn_9, 3, 2, 1, 1)
        self.btn_5 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_5.setFont(font)
        self.btn_5.setObjectName("btn_5")
        self.gridLayout.addWidget(self.btn_5, 2, 1, 1, 1)
        self.btn_0 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_0.setFont(font)
        self.btn_0.setObjectName("btn_0")
        self.gridLayout.addWidget(self.btn_0, 4, 1, 1, 1)
        self.btn_sub = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_sub.setFont(font)
        self.btn_sub.setObjectName("btn_sub")
        self.gridLayout.addWidget(self.btn_sub, 2, 3, 1, 1)
        self.btn_8 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_8.setFont(font)
        self.btn_8.setObjectName("btn_8")
        self.gridLayout.addWidget(self.btn_8, 3, 1, 1, 1)
        self.btn_clear = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_clear.setFont(font)
        self.btn_clear.setObjectName("btn_clear")
        self.gridLayout.addWidget(self.btn_clear, 4, 0, 1, 1)
        self.btn_mul = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_mul.setFont(font)
        self.btn_mul.setObjectName("btn_mul")
        self.gridLayout.addWidget(self.btn_mul, 3, 3, 1, 1)
        self.btn_3 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_3.setFont(font)
        self.btn_3.setObjectName("btn_3")
        self.gridLayout.addWidget(self.btn_3, 0, 2, 1, 1)
        self.btn_div = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_div.setFont(font)
        self.btn_div.setObjectName("btn_div")
        self.gridLayout.addWidget(self.btn_div, 4, 3, 1, 1)
        self.btn_plus = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_plus.setFont(font)
        self.btn_plus.setObjectName("btn_plus")
        self.gridLayout.addWidget(self.btn_plus, 0, 3, 1, 1)
        self.btn_6 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_6.setFont(font)
        self.btn_6.setObjectName("btn_6")
        self.gridLayout.addWidget(self.btn_6, 2, 2, 1, 1)
        self.btn_2 = QtWidgets.QPushButton(self.gridLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(20)
        font.setBold(True)
        font.setWeight(75)
        self.btn_2.setFont(font)
        self.btn_2.setObjectName("btn_2")
        self.gridLayout.addWidget(self.btn_2, 0, 1, 1, 1)

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

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "计算器"))
        self.btn_equal.setText(_translate("Form", "="))
        self.btn_4.setText(_translate("Form", "4"))
        self.btn_7.setText(_translate("Form", "7"))
        self.btn_1.setText(_translate("Form", "1"))
        self.btn_9.setText(_translate("Form", "9"))
        self.btn_5.setText(_translate("Form", "5"))
        self.btn_0.setText(_translate("Form", "0"))
        self.btn_sub.setText(_translate("Form", "-"))
        self.btn_8.setText(_translate("Form", "8"))
        self.btn_clear.setText(_translate("Form", "清除"))
        self.btn_mul.setText(_translate("Form", "*"))
        self.btn_3.setText(_translate("Form", "3"))
        self.btn_div.setText(_translate("Form", "/"))
        self.btn_plus.setText(_translate("Form", "+"))
        self.btn_6.setText(_translate("Form", "6"))
        self.btn_2.setText(_translate("Form", "2"))

三. 主程序设计

1. 最小主程序设计,不响应button事件

运行下面的代码可以显示刚才做好的UI。

程序中,自定义的类“MyWindow”继承了QWidget(PyQt5中的类)和Ui_Form(刚才我们自己设计的UI的类名);在__init__函数中,呼叫了QWidget的__init__和Ui_Form的setupUi完成了初始化。

在主程序中,完成了MyWindow类的实例化和显示动作。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
from CalUi import Ui_Form


class MyWindow(QWidget, Ui_Form):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setupUi(self)
 

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()    
    
    win.show()
    sys.exit(app.exec_())

2. 加入代码,响应button事件(由Qt的信号和槽实现)

下面是对QT的信号和槽的介绍,通俗地将,就是绑定相关的事件(比如click)和方法。使用的函数为“connect()”,比如,下面的实例中,“win.btn_clear.clicked.connect(win.btnClear_clicked)”, 就是绑定了btnClear的事件和方法。

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。)

信号和槽是Qt特有的信息传输机制,是Qt设计程序的重要基础,它可以让互不干扰的对象建立一种联系。

槽的本质是类的成员函数,其参数可以是任意类型的。和普通C++成员函数几乎没有区别,它可以是虚函数;也可以被重载;可以是公有的、保护的、私有的、也可以被其他C++成员函数调用。唯一区别的是:槽可以与信号连接在一起,每当和槽连接的信号被发射的时候,就会调用这个槽。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
from CalUi import Ui_Form


class MyWindow(QWidget, Ui_Form):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setupUi(self)
 
    def btnClear_clicked(self):
        self.lineEdit.clear()
        

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()
    
    win.btn_clear.clicked.connect(win.btnClear_clicked)    
    
    win.show()
    sys.exit(app.exec_())

3. 计算器的详细实现代码如下

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
from CalUi import Ui_Form


class MyWindow(QWidget, Ui_Form):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setupUi(self)
 
    def btnClear_clicked(self):
        self.lineEdit.clear()
        
    def btn1_clicked(self):
        self.lineEdit.insert("1")
        
    def btn2_clicked(self):
        self.lineEdit.insert("2")
        
    def btn3_clicked(self):
        self.lineEdit.insert("3")
        
    def btn4_clicked(self):
        self.lineEdit.insert("4")
        
    def btn5_clicked(self):
        self.lineEdit.insert("5")
        
    def btn6_clicked(self):
        self.lineEdit.insert("6")
        
    def btn7_clicked(self):
        self.lineEdit.insert("7")
        
    def btn8_clicked(self):
        self.lineEdit.insert("8")
        
    def btn9_clicked(self):
        self.lineEdit.insert("9")
        
    def btn0_clicked(self):
        self.lineEdit.insert("0")
        
    def btnPlus_clicked(self):
        self.lineEdit.insert(" + ")
        
    def btnSub_clicked(self):
        self.lineEdit.insert(" - ")
        
    def btnMul_clicked(self):
        self.lineEdit.insert(" * ")
        
    def btnDiv_clicked(self):
        self.lineEdit.insert(" / ")
        
    def btnEqual_clicked(self):
        text = self.lineEdit.text()
        self.lineEdit.insert(' = %.2f' % (eval(text)))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()
    
    win.btn_clear.clicked.connect(win.btnClear_clicked)
    win.btn_1.clicked.connect(win.btn1_clicked)
    win.btn_2.clicked.connect(win.btn2_clicked)
    win.btn_3.clicked.connect(win.btn3_clicked)
    win.btn_4.clicked.connect(win.btn4_clicked)
    win.btn_5.clicked.connect(win.btn5_clicked)
    win.btn_6.clicked.connect(win.btn6_clicked)
    win.btn_7.clicked.connect(win.btn7_clicked)
    win.btn_8.clicked.connect(win.btn8_clicked)
    win.btn_9.clicked.connect(win.btn9_clicked)
    win.btn_0.clicked.connect(win.btn0_clicked)
    win.btn_plus.clicked.connect(win.btnPlus_clicked)
    win.btn_sub.clicked.connect(win.btnSub_clicked)
    win.btn_mul.clicked.connect(win.btnMul_clicked)
    win.btn_div.clicked.connect(win.btnDiv_clicked)
    win.btn_equal.clicked.connect(win.btnEqual_clicked)
    
    
    win.show()
    sys.exit(app.exec_())

四. 测试

运行完整代码,进行算术运行,界面如下。

五. 小结

PyQt5设计UI简单方便,功能强大,是Python中十分出色的UI库。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐