用 PyQt 开发一个桌面计算器:从零到完整实战指南

作者:Python私教日期:2025/11/9

作者:张大鹏
时间:2025-11-05
标签:Python、PyQt5、GUI、桌面开发、实战教程


一、前言

在桌面应用开发中,计算器 是一个非常适合入门的练手项目。
它涉及到图形界面设计、事件绑定、信号槽机制、布局管理等核心概念。

今天我们将使用 PyQt5(同样适用于 PyQt6)一步步实现一个可用的计算器程序,从 UI 布局到功能逻辑完整讲解。

最终效果如下👇:

  • 支持加减乘除和小数运算;
  • 按钮布局整齐;
  • 可通过按钮或键盘输入操作;
  • 界面美观,可打包为独立应用。

二、项目环境

项目依赖说明
Python 3.8+推荐使用 3.9 或以上版本
PyQt5图形界面开发框架
Qt Designer(可选)可视化 UI 设计工具

安装命令:

1pip install PyQt5
2

三、项目结构

我们将项目组织如下:

1pyqt_calculator/
23├── main.py              # 主程序入口
4├── calculator.ui        # Qt Designer 设计文件(可选)
5└── ui_calculator.py     # UI 转换后的 Python 文件
6

四、第一步:构建界面

我们先手动创建一个简单的界面,不依赖 Qt Designer。

1# main.py
2from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton, QLineEdit, QVBoxLayout
3from PyQt5.QtCore import Qt
4import sys
5
6
7class Calculator(QWidget):
8    def __init__(self):
9        super().__init__()
10        self.setWindowTitle("PyQt 计算器")
11        self.setFixedSize(300, 400)
12        self.init_ui()
13
14    def init_ui(self):
15        # 显示区域
16        self.display = QLineEdit()
17        self.display.setAlignment(Qt.AlignRight)
18        self.display.setReadOnly(True)
19        self.display.setStyleSheet("font-size: 24px; padding: 10px;")
20
21        # 按钮布局
22        buttons = {
23            '7': (0, 0), '8': (0, 1), '9': (0, 2), '/': (0, 3),
24            '4': (1, 0), '5': (1, 1), '6': (1, 2), '*': (1, 3),
25            '1': (2, 0), '2': (2, 1), '3': (2, 2), '-': (2, 3),
26            '0': (3, 0), '.': (3, 1), 'C': (3, 2), '+': (3, 3),
27            '=': (4, 0, 1, 4)
28        }
29
30        grid = QGridLayout()
31        for text, pos in buttons.items():
32            button = QPushButton(text)
33            button.setStyleSheet("font-size: 20px; height: 50px;")
34            if len(pos) == 2:
35                grid.addWidget(button, pos[0], pos[1])
36            else:
37                grid.addWidget(button, pos[0], pos[1], pos[2], pos[3])
38            button.clicked.connect(self.on_button_clicked)
39
40        layout = QVBoxLayout()
41        layout.addWidget(self.display)
42        layout.addLayout(grid)
43        self.setLayout(layout)
44
45    def on_button_clicked(self):
46        sender = self.sender().text()
47        current = self.display.text()
48
49        if sender == "C":
50            self.display.clear()
51        elif sender == "=":
52            try:
53                result = str(eval(current))
54                self.display.setText(result)
55            except Exception:
56                self.display.setText("Error")
57        else:
58            self.display.setText(current + sender)
59
60
61if __name__ == "__main__":
62    app = QApplication(sys.argv)
63    window = Calculator()
64    window.show()
65    sys.exit(app.exec_())
66

运行后即可看到一个基础的计算器界面。


五、第二步:添加键盘输入支持

许多用户习惯直接使用键盘输入,我们可以重写 keyPressEvent 方法:

1def keyPressEvent(self, event):
2    key = event.key()
3    if key == Qt.Key_Return or key == Qt.Key_Enter:
4        self.on_button_clicked()  # 模拟 "="
5    elif key == Qt.Key_Backspace:
6        self.display.setText(self.display.text()[:-1])
7    else:
8        text = event.text()
9        if text.isdigit() or text in ['+', '-', '*', '/', '.']:
10            self.display.setText(self.display.text() + text)
11

这样计算器即可同时响应键盘输入。


六、第三步:改进计算逻辑

直接使用 eval() 虽然简单,但存在安全风险。
我们可以使用 Python 内置的 ast 模块安全地解析表达式。

1import ast
2import operator as op
3
4operators = {
5    ast.Add: op.add,
6    ast.Sub: op.sub,
7    ast.Mult: op.mul,
8    ast.Div: op.truediv
9}
10
11def safe_eval(expr):
12    node = ast.parse(expr, mode='eval').body
13    def _eval(node):
14        if isinstance(node, ast.Num):
15            return node.n
16        elif isinstance(node, ast.BinOp):
17            return operators[type(node.op)](_eval(node.left), _eval(node.right))
18        else:
19            raise TypeError(node)
20    return _eval(node)
21

替换掉 eval(current) 部分即可更安全地计算。


七、第四步:美化界面

使用 Qt Style Sheet (QSS) 进行样式美化:

1self.setStyleSheet("""
2    QWidget {
3        background-color: #2E3440;
4    }
5    QLineEdit {
6        background: #3B4252;
7        color: #ECEFF4;
8        border: none;
9        border-radius: 5px;
10    }
11    QPushButton {
12        background-color: #4C566A;
13        color: #ECEFF4;
14        border-radius: 8px;
15    }
16    QPushButton:hover {
17        background-color: #5E81AC;
18    }
19    QPushButton:pressed {
20        background-color: #81A1C1;
21    }
22""")
23

界面将呈现出类似现代深色主题的视觉效果。


八、第五步:项目打包

当应用开发完成后,我们可以使用 pyinstaller 打包为可执行文件:

1pip install pyinstaller
2pyinstaller -F -w main.py
3
  • -F:打包为单文件
  • -w:去掉控制台窗口(适合 GUI 应用)

生成的可执行文件在 dist/ 目录中。


九、扩展思路

这个项目的核心结构可以进一步扩展:

  • 添加括号与优先级运算
  • 显示历史计算记录
  • 支持科学计算(sin、cos、sqrt 等)
  • 国际化(i18n)
  • 保存用户偏好与主题

通过这些改进,你可以将这个小项目打磨成一个完整的专业级桌面工具。


十、总结

通过本篇实战,我们掌握了以下关键技能:

  • 使用 PyQt5 搭建窗口与控件布局;
  • 理解 信号与槽 的事件机制;
  • 构建计算逻辑与安全求值;
  • 使用 QSS 美化界面;
  • 打包发布桌面应用。

PyQt 的强大不仅在于能做出“好看的界面”,更在于它与 Python 的生态融合:
你可以轻松把它扩展成数据可视化工具、AI 模型控制台、图像处理前端等等。

下一步,不妨试着给这个计算器加上图表或语音输入功能,体验 PyQt 真正的扩展性。


用 PyQt 开发一个桌面计算器:从零到完整实战指南》 是转载文章,点击查看原文


相关推荐


React+Tailwind CSS+Shadcn UI
再希2025/11/7

推荐常用网址 yhttps://react.dev/learn/describing-the-ui 使用 Vite 安装 Tailwind CSS - Tailwind CSS Introduction - shadcn/ui 下面这个地址记录了前端常用的命令,以及学习教程等,推荐给各位 https://www.houdunren.com/doc/article/21/208 创建react项目首先需要准备好nodeJS环境,我这里使用的是vite脚手架 步骤如下: 使用 Vit


前端新手必看!困扰90%人的10个JavaScript问题,一次性帮你解决
良山有风来2025/11/4

是不是经常被JavaScript的各种“奇怪”行为搞到头大?明明照着教程写代码,结果运行起来却各种报错?别担心,这些问题几乎每个前端新手都会遇到。 今天我就把新手最容易踩坑的10个JavaScript问题整理出来,每个问题都会给出清晰的解释和实用的解决方案。看完这篇文章,你就能彻底理解这些“坑”背后的原理,写出更健壮的代码。 变量提升的陷阱 很多新手都会困惑,为什么变量在声明之前就能使用?这其实是JavaScript的变量提升机制在作怪。 console.log(myName); // 输出:u


低空经济网络安全体系
芯盾时代2025/10/31

为了促进低空经济的稳健发展,构建完善的网络安全体系势在必行。低空经济网络安全业务体系的重点在于将安全因素深度融入业务决策流程,确保在满足各类场景需求的同时,安全措施得以全面落实。产业合作体系则强调产学研用管多方的协同合作,以期通过集体努力完善相关政策、加强监管、推动技术创新和标准制定。同时,需要特别关注机载智能算法的相关安全。威胁定级与应急防护体系聚焦安全威胁的分类分级和应急处置,旨在构建低空经济网络安全的主动防御能力。供应链安全体系则着眼于生产制造全链条的安全管理,从而确保低空经济供应链的安全


【普中STM32F1xx开发攻略--标准库版】-- 第 9 章 STM32 固件库介绍
普中科技2025/10/29

(1)实验平台: 普中STM32F103朱雀开发板https://item.taobao.com/item.htm?id=620302685024普中STM32F103玄武开发板https://item.taobao.com/item.htm?id=603479028876(2)资料下载:普中科技-各型号产品资料下载链接         前面章节为大家简单介绍了如何使用寄存器点亮开发板上 LED, 这种开发方式显然是不适合大众, 对于 STM32 这样庞大的芯片, 内部寄存器实在太多,


TraceId如何在Spring-Cloud微服务的REST调用中传递
青鱼入云2025/10/26

文章目录 推荐方案:基于Spring Cloud Sleuth(无侵入,官方推荐)1. 集成Sleuth2. 核心原理3. 日志配置(输出traceId)4. 验证 自定义实现方案(不依赖Sleuth,了解原理)1. 定义常量(统一Header键)2. 发送端:通过拦截器传递traceId(1)RestTemplate调用场景(2)Feign调用场景 3. 接收端:通过过滤器提取traceId并设置到MDC 关键注意事项 在Spring Cloud微服务


Python 的内置函数 classmethod
IMPYLH2025/10/23

Python 内建函数列表 > Python 的内置函数 classmethod Python 的内置函数 classmethod 是一个装饰器,用于将一个方法标记为类方法。类方法属于类本身,而不是类的实例,因此可以在不创建实例的情况下直接通过类名调用。 def classmethod(fn): ''' 把一个方法封装成类方法 :param fn: 要封装的方法 :return: 封装后的方法 ''' 使用 @classmethod 装饰器来定义


攻防世界—easyupload
风语者日志2025/10/22

知识点补充 .user.ini php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。 常用配置 auto_prepend_file = <filename> //包含在文件头 auto_append_file = <filename> //包含在文件尾 一句话木马变种 这里的题目由


数据结构(顺序表和链表)
泡泡鱼(敲代码中)2025/10/21

数据结构(题) 一、顺序表 1、移除元素   int removeElement(int* nums, int numsSize, int val) {     int dst = 0;     int src = 0;     while(src<numsSize)     {         if(nums[src]!=val)         {             nums[dst]=nums[src];             dst++;     


运放的 Input Offset Drift(输入失调漂移)
Heismk2025/10/19

Input Offset Drift(输入失调漂移)是衡量运算放大器(或其他精密放大器件)性能的关键指标,用于描述温度变化时输入失调电压的变化率,直接反映器件在温度波动环境下的稳定性。 核心定义 输入失调漂移指的是:当环境温度每变化 1℃ 时,运放的**输入失调电压(Input Offset Voltage)**所发生的变化量,单位通常为 μV/℃(微伏每摄氏度)或 nV/℃(纳伏每摄氏度)。 输入失调电压(Vos):理想运放输入短路时输出应为 0,但实际器件因内部工艺差异,需在输入端施加一个微


Compose 自定义布局和图形
Best_Jerry2025/10/18

Advanced layout concepts - MAD Skills Compose 提供各种开箱即用型解决方案,可帮助您快速轻松地从头开始构建界面。但是,如果您需要更进一步,以实现完全自定义的界面,该怎么办?详细了解高级布局概念,以便自行构建自定义布局,让您的设计实现更上一层楼。 1. Advanced Layout Concepts Layout 这一术语在 Compose 中有多种含义: 以下是每种含义的相关解释: 2. Layout phase and constraint

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0