PyQt5实战:用QtDesigner设计计算器UI并用PyUIC转换为Python代码
本文是上篇《PyQt5 入门实战:安装、QtDesigner 设计与 PyUIC 转换完整指南》的续篇。
上篇完成了环境搭建和工具配置,本篇直接上手实战——用 Qt Designer 设计一个简易计算器界面,通过 PyUIC 转换代码,再编写业务逻辑,完整跑通从设计到运行的全流程。环境:Python 3.9 + PyQt5 5.15.4 + PyCharm
一、项目结构总览
本次计算器项目包含三个核心文件:
设计计算器/ ├── untitled.ui # Qt Designer 保存的界面描述文件(XML 格式) ├── untitled.py # PyUIC 自动生成的 UI 类(勿手动修改!) └── main.py # 手动编写的业务逻辑 + 程序入口效果图
三个文件职责分离:
untitled.ui:由 Qt Designer 负责,描述界面长什么样untitled.py:由 PyUIC 负责,把.ui翻译成 Python 类main.py:由开发者负责,继承 UI 类并绑定业务逻辑
二、Qt Designer 界面设计
2.1 本例用到的控件
从截图中的 Widget Box 可以看到,Qt Designer 左侧控件库的常用分类:
| 控件 | 分类 | 本例用途 |
|---|---|---|
| Push Button | Buttons | 数字键 0-9、运算符 ±*/、等号、清空,共 17 个按钮 |
| Text Edit | Input Widgets | 标题显示框(textEdit)和表达式输入/结果显示框(textEdit_2) |
| Line Edit | Input Widgets | 单行文本框(本例未使用,但常用于密码/搜索框) |
| Label | Display Widgets | 静态文字/图片显示(本例未使用) |
本例全程只用了Push Button和Text Edit两种控件,简单高效。
2.2 界面布局结构
计算器界面由以下层次组成:
MainWindow(主窗口,1297×949) ├── textEdit(标题框:显示"简易计算器",28pt 大字,居中对齐) ├── widget(VBoxLayout 容器,位置 270,120,大小 499×261) │ ├── textEdit_2(表达式输入/结果显示区) │ └── verticalLayout(垂直布局) │ ├── horizontalLayout(第1行:1 2 3 + -) │ ├── horizontalLayout_2(第2行:4 5 6 * /) │ └── horizontalLayout_3(第3行:7 8 9 0 =) └── pushButton_16(清空按钮,独立于 widget 外)布局设计要点:
- 数字和运算符按钮用HBoxLayout(水平布局)排成3行,每行5个
- 三行用VBoxLayout(垂直布局)自动均匀分配高度
- 清空按钮放在 widget 外单独定位,避免影响整体布局
2.3 在 Qt Designer 中操作步骤
- 启动 Qt Designer:PyCharm → 工具 → 外部工具 → QtDesigner
- 选择 Main Window 模板,点击创建
- 拖入 Text Edit:从左侧 Widget Box → Input Widgets → Text Edit,拖到画布顶部,在属性编辑器中设置 HTML 内容为"简易计算器"(28pt,居中)
- 拖入容器 Widget:拖一个 Widget 到画布中间,右键 → 布局 → 垂直布局
- 拖入第二个 Text Edit:放到 widget 中,作为表达式输入框
- 添加三行按钮:每行先拖5个 Push Button,全选后右键 → 布局 → 水平布局
- 设置按钮文字:在属性编辑器中修改
text属性,依次设置为 1~9、0、+、-、*、/、= - 添加清空按钮:拖一个 Push Button 到 widget 外,设置 text 为"清空",调整字号为 18pt 加粗
- 保存:Ctrl+S 保存为
untitled.ui
三、PyUIC 转换 .ui 为 .py
3.1 转换操作
保存完untitled.ui后:
- 在 PyCharm 项目面板中,右键
untitled.ui - 选择
外部工具→PyUIC - 等待几秒,自动在同目录生成
untitled.py
3.2 生成的 untitled.py 代码解析
PyUIC 生成的文件包含一个Ui_MainWindow类,核心有两个方法:
setupUi() — 创建所有控件
classUi_MainWindow(object):defsetupUi(self,MainWindow):# 1. 设置主窗口尺寸MainWindow.setObjectName("MainWindow")MainWindow.resize(1297,949)# 2. 创建标题文本框(绝对定位)self.textEdit=QtWidgets.QTextEdit(self.centralwidget)self.textEdit.setGeometry(QtCore.QRect(320,10,381,87))# 3. 创建清空按钮(绝对定位 + 大号粗体字)self.pushButton_16=QtWidgets.QPushButton(self.centralwidget)self.pushButton_16.setGeometry(QtCore.QRect(450,410,121,51))font=QtGui.QFont()font.setPointSize(18)font.setBold(True)self.pushButton_16.setFont(font)# 4. 创建 widget 容器(VBoxLayout)self.widget=QtWidgets.QWidget(self.centralwidget)self.widget.setGeometry(QtCore.QRect(270,120,499,261))self.verticalLayout_2=QtWidgets.QVBoxLayout(self.widget)# 5. 在 widget 内创建表达式框self.textEdit_2=QtWidgets.QTextEdit(self.widget)self.verticalLayout_2.addWidget(self.textEdit_2)# 6. 创建三行按钮(HBoxLayout × 3)self.horizontalLayout=QtWidgets.QHBoxLayout()self.pushButton_1=QtWidgets.QPushButton(self.widget)self.horizontalLayout.addWidget(self.pushButton_1)# ... 共 15 个数字/运算符按钮# 7. 末尾绑定所有信号槽(重点!)self.pushButton_16.clicked.connect(self.textEdit_2.clear)self.pushButton_15.clicked.connect(MainWindow.result)# ...retranslateUi() — 设置控件文字
defretranslateUi(self,MainWindow):_translate=QtCore.QCoreApplication.translate# 标题框 HTML 内容self.textEdit.setHtml(_translate("MainWindow","...<span style='font-size:28pt;'>简易计算器</span>..."))# 各按钮文字self.pushButton_16.setText(_translate("MainWindow","清空"))self.pushButton_1.setText(_translate("MainWindow","1"))self.pushButton_2.setText(_translate("MainWindow","2"))# ... 依次设置所有按钮self.pushButton_15.setText(_translate("MainWindow","="))注意:文件头部的注释明确警告:
WARNING: Any manual changes made to this file will be lost when pyuic5 is run again.
不要在 untitled.py 中写任何业务代码,否则下次重新生成会全部丢失!
四、信号槽连接详解
PyUIC 在setupUi()末尾自动生成了所有信号槽连接:
# untitled.py setupUi() 末尾 —— 信号槽自动连接self.pushButton_16.clicked.connect(self.textEdit_2.clear)# 清空按钮self.pushButton_15.clicked.connect(MainWindow.result)# = 计算结果self.pushButton_10.clicked.connect(MainWindow.chu)# / 除法self.pushButton_5.clicked.connect(MainWindow.jian)# - 减法self.pushButton_9.clicked.connect(MainWindow.cheng)# * 乘法self.pushButton_4.clicked.connect(MainWindow.jia)# + 加法# 数字键 0-9 全部连接同一个 put 函数self.pushButton_1.clicked.connect(MainWindow.put)self.pushButton_2.clicked.connect(MainWindow.put)# ...self.pushButton_14.clicked.connect(MainWindow.put)信号槽连接规律:
- 清空→
textEdit_2.clear(Qt 内置槽,无需手写) - 运算符→ 各自对应的
jia / jian / cheng / chu方法 - 数字 0-9→ 全部连接
put方法(用sender()区分是哪个按钮)
五、main.py 业务逻辑详解
fromPyQt5importQtCore,QtGui,QtWidgetsfromPyQt5.QtWidgetsimportQMainWindow,QMessageBoxfromuntitledimportUi_MainWindow# 导入 PyUIC 生成的 UI 类importsysclassPyQtMainEntry(QMainWindow,Ui_MainWindow):# 多重继承:窗口功能 + UI 结构def__init__(self):super().__init__()self.setupUi(self)# 调用 UI 类的 setupUi,完成所有控件创建和信号槽绑定# ———— 数字输入:0-9 共用同一个槽函数 ————defput(self):btn_text=self.sender().text()# 关键:获取点击按钮的文字(1/2/.../0)current_text=self.textEdit_2.toPlainText()self.textEdit_2.setPlainText(current_text+btn_text)# 追加字符# ———— 四则运算符 ————defjia(self):current_text=self.textEdit_2.toPlainText()self.textEdit_2.setPlainText(current_text+"+")defjian(self):current_text=self.textEdit_2.toPlainText()self.textEdit_2.setPlainText(current_text+"-")defcheng(self):current_text=self.textEdit_2.toPlainText()self.textEdit_2.setPlainText(current_text+"*")defchu(self):current_text=self.textEdit_2.toPlainText()self.textEdit_2.setPlainText(current_text+"/")# ———— 计算结果 ————defresult(self):try:expression=self.textEdit_2.toPlainText()# 读取当前表达式res=str(eval(expression))# eval 直接计算字符串表达式self.textEdit_2.setPlainText(res)# 把结果写回文本框exceptExceptionase:QMessageBox.warning(self,"错误","表达式无效!")# 弹出警告框self.textEdit_2.clear()# 清空错误输入if__name__=="__main__":app=QtWidgets.QApplication(sys.argv)window=PyQtMainEntry()window.show()sys.exit(app.exec_())关键技术点解析
1. 多重继承
classPyQtMainEntry(QMainWindow,Ui_MainWindow):同时继承两个类:
QMainWindow:提供窗口的关闭/最大化/最小化等原生功能Ui_MainWindow:提供 setupUi() 方法,把所有控件"安装"到窗口上
2. sender() 的妙用
defput(self):btn_text=self.sender().text()# 谁触发了信号,谁就是 sender14 个数字按钮共用put()一个函数。self.sender()返回触发信号的对象(即被点击的按钮),再调用.text()获取按钮显示的文字(“1”/“2”/…/“0”),无需写 14 个重复函数,代码极简。
3. eval() 计算表达式
res=str(eval(expression))eval()把字符串当 Python 表达式执行,"1+2*3"会按数学优先级计算得 7。用try-except包裹防止非法输入崩溃。
注意:
eval()在生产环境中存在安全风险,学习和本地工具使用没有问题,面向公网的应用应使用专门的表达式解析库(如ast.literal_eval或mathparser)替代。
六、完整开发流程回顾
Step 1 Qt Designer 拖拽设计界面 ↓ 保存为 untitled.ui Step 2 PyCharm 右键 untitled.ui → 外部工具 → PyUIC ↓ 自动生成 untitled.py(含 Ui_MainWindow 类) Step 3 新建 main.py,继承 Ui_MainWindow class PyQtMainEntry(QMainWindow, Ui_MainWindow) Step 4 在 __init__ 中调用 self.setupUi(self) (控件和信号槽全部就位) Step 5 在 main.py 中补充槽函数(put/jia/jian/cheng/chu/result) Step 6 python main.py 运行七、总结
| 文件 | 生成方式 | 内容 | 可手动修改? |
|---|---|---|---|
untitled.ui | Qt Designer 拖拽保存 | XML 格式界面描述 | 可以,但建议在 Designer 中修改 |
untitled.py | PyUIC 自动生成 | Ui_MainWindow类 | 不要修改,重新运行 PyUIC 会覆盖 |
main.py | 手动编写 | 业务逻辑 + 程序入口 | 自由修改 |
本例核心思想:
- Qt Designer 只管"界面长什么样"
- PyUIC 只管"把界面翻译成 Python"
- main.py 只管"按钮按下后发生什么"
三者职责分离,互不干扰,这正是 Qt 设计器工作流最大的优势。
系列导航
- 上一篇:PyQt5 入门实战:安装、QtDesigner 设计与 PyUIC 转换完整指南
- 本篇:PyQt5 实战 — 用 Qt Designer 设计计算器 UI 并用 PyUIC 转换为 Python 代码
只管"把界面翻译成 Python"
- main.py 只管"按钮按下后发生什么"
