当前位置: 首页 > news >正文

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 ButtonButtons数字键 0-9、运算符 ±*/、等号、清空,共 17 个按钮
Text EditInput Widgets标题显示框(textEdit)和表达式输入/结果显示框(textEdit_2)
Line EditInput Widgets单行文本框(本例未使用,但常用于密码/搜索框)
LabelDisplay Widgets静态文字/图片显示(本例未使用)

本例全程只用了Push ButtonText 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 中操作步骤

  1. 启动 Qt Designer:PyCharm → 工具 → 外部工具 → QtDesigner
  2. 选择 Main Window 模板,点击创建
  3. 拖入 Text Edit:从左侧 Widget Box → Input Widgets → Text Edit,拖到画布顶部,在属性编辑器中设置 HTML 内容为"简易计算器"(28pt,居中)
  4. 拖入容器 Widget:拖一个 Widget 到画布中间,右键 → 布局 → 垂直布局
  5. 拖入第二个 Text Edit:放到 widget 中,作为表达式输入框
  6. 添加三行按钮:每行先拖5个 Push Button,全选后右键 → 布局 → 水平布局
  7. 设置按钮文字:在属性编辑器中修改text属性,依次设置为 1~9、0、+、-、*、/、=
  8. 添加清空按钮:拖一个 Push Button 到 widget 外,设置 text 为"清空",调整字号为 18pt 加粗
  9. 保存:Ctrl+S 保存为untitled.ui

三、PyUIC 转换 .ui 为 .py

3.1 转换操作

保存完untitled.ui后:

  1. 在 PyCharm 项目面板中,右键untitled.ui
  2. 选择外部工具PyUIC
  3. 等待几秒,自动在同目录生成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()# 谁触发了信号,谁就是 sender

14 个数字按钮共用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_evalmathparser)替代。


六、完整开发流程回顾

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.uiQt Designer 拖拽保存XML 格式界面描述可以,但建议在 Designer 中修改
untitled.pyPyUIC 自动生成Ui_MainWindow不要修改,重新运行 PyUIC 会覆盖
main.py手动编写业务逻辑 + 程序入口自由修改

本例核心思想:

  • Qt Designer 只管"界面长什么样"
  • PyUIC 只管"把界面翻译成 Python"
  • main.py 只管"按钮按下后发生什么"

三者职责分离,互不干扰,这正是 Qt 设计器工作流最大的优势。


系列导航

  • 上一篇:PyQt5 入门实战:安装、QtDesigner 设计与 PyUIC 转换完整指南
  • 本篇:PyQt5 实战 — 用 Qt Designer 设计计算器 UI 并用 PyUIC 转换为 Python 代码
    只管"把界面翻译成 Python"
  • main.py 只管"按钮按下后发生什么"
http://www.jsqmd.com/news/673620/

相关文章:

  • THREE.MeshLine入门教程:10分钟创建惊艳3D线条效果
  • YOLOv5至YOLOv12升级:番茄新鲜程度检测系统的设计与实现(完整代码+界面+数据集项目)
  • 国产大模型托管平台全景观察:四大平台如何赋能AI开发者生态
  • 终极docker2exe错误码手册:快速解决容器转可执行文件的常见问题
  • 手把手教你用Verilog写一个8点流水线FFT(附完整代码与Matlab验证)
  • Windows更新修复终极指南:一键重置工具完全教程
  • 告别网络依赖!用Cesium + 离线瓦片打造内网可用的三维GIS应用(保姆级部署教程)
  • 告别串口助手!用NXP FreeMaster 3.0实时调PID,图形化调试真香了
  • 2026年国内五大头部品牌营销公司深度测评与权威指南 - GEO优化
  • Java中CompletableFuture使用不当引发的线程池耗尽
  • ADIS16470数据精度全解析:从16位Burst到32位寄存器读取,哪种方案更适合你的项目?
  • 在中标麒麟上从源码编译QGIS 3.4.7:一份踩坑无数的依赖库安装指南
  • 从亚稳态到稳定系统:深入芯片内部的异步复位同步释放电路设计
  • AI Agent Harness Engineering 与人类员工协同工作:管理层需要知道的组织变革
  • 别再被直觉骗了!用Python模拟10000次,带你彻底搞懂三门问题(蒙提霍尔悖论)
  • 别再只用球面镜了!手把手教你用Zemax OpticStudio的切比雪夫多项式设计离轴抛物面
  • 3步实现QQ空间备份:永久保存青春记忆的智能工具
  • 华为Pura X上新:型格配色+高配置+鸿蒙6.1,满足高端用户折叠旗舰使用需求
  • await FtpUploadFileAsync(orgTiffFilePath) 是否可以去掉 await
  • 终极指南:如何用OCAT轻松搞定OpenCore配置难题
  • LSTM实战(上篇):微博情感分析——词表构建与数据集加载
  • 程序猿成长计划:MongoDB实战应用与最佳实践
  • Multrin与其他窗口管理工具对比:优势和特点分析
  • 深入TF-A启动流程:BL2阶段如何从FIP文件中精准“捞出”你需要的镜像?
  • 别再折腾了!Linux桌面环境(GNOME/KDE)下iPhone即插即用指南,附常见问题排查
  • Tape测试框架插件生态系统:15+个美化器和报告器终极指南
  • 题解:洛谷 AT_abc396_a [ABC396A] Triple Four
  • Go错误处理与panic恢复
  • 安装 openclaw,hermes 慢的想发疯,fast-mirror-skill 来救了
  • 终极tRPC远程协作指南:类型安全API的10个高效工作技巧