first commit
This commit is contained in:
commit
b25f9f97b5
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
.pytest_cache/
|
||||||
|
.idea/
|
||||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
10
.idea/calculator.iml
generated
Normal file
10
.idea/calculator.iml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.12 (calculator)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredIdentifiers">
|
||||||
|
<list>
|
||||||
|
<option value="DrissionPage.*" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (calculator)" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/calculator.iml" filepath="$PROJECT_DIR$/.idea/calculator.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
88
README.md
Normal file
88
README.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# 简易计算器GUI程序
|
||||||
|
|
||||||
|
 <!-- 需添加实际截图 -->
|
||||||
|
|
||||||
|
[](https://www.python.org/)
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **四则运算**:支持加(+)、减(-)、乘(×)、除(÷)基本运算
|
||||||
|
- **连续计算**:自动保留计算结果用于后续运算
|
||||||
|
- **智能显示**:
|
||||||
|
- 自动去除小数点后多余的零
|
||||||
|
- 大数字自动适应显示区域
|
||||||
|
- **错误处理**:
|
||||||
|
- 除零错误检测与提示
|
||||||
|
- 无效操作拦截
|
||||||
|
- 异常崩溃防护
|
||||||
|
- **交互设计**:
|
||||||
|
- 退格键(←)支持
|
||||||
|
- 一键清零(C)功能
|
||||||
|
- 实时输入反馈
|
||||||
|
- **界面特性**:
|
||||||
|
- 半透明窗口效果
|
||||||
|
- 响应式布局
|
||||||
|
- 中文宋体显示
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
- Python 3.7+
|
||||||
|
- Tkinter(通常随Python默认安装)
|
||||||
|
|
||||||
|
### 安装与运行
|
||||||
|
```bash
|
||||||
|
1. 克隆仓库
|
||||||
|
git clone https://github.com/yourusername/calculator-gui.git
|
||||||
|
2. 进入项目目录
|
||||||
|
cd calculator-gui
|
||||||
|
3. 运行程序
|
||||||
|
python calculator.py
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 技术细节
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- **核心框架**: Python标准库 Tkinter
|
||||||
|
- **状态管理**: 全局变量跟踪模式
|
||||||
|
- **错误处理**: Try/Except异常捕获机制
|
||||||
|
- **界面布局**: Grid网格布局系统
|
||||||
|
|
||||||
|
### 项目结构
|
||||||
|
```python
|
||||||
|
calculator.py
|
||||||
|
├── 全局状态变量 # current_input, first_operand, operator
|
||||||
|
├── 样式配置常量 # COLORS, FONT, LAYOUT
|
||||||
|
├── 事件处理函数 # on_number_click, on_operator_click, calculate等
|
||||||
|
├── UI构建模块 # 结果显示区、操作按钮矩阵、等号按钮
|
||||||
|
└── 主程序循环 # root.mainloop()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
| 版本号 | 作者 | 发布日期 | 主要变更 |
|
||||||
|
|--------|----|------------|----------------------|
|
||||||
|
| v1.0.0 | 鲁豫 | 2025-04-15 | 完善代码注释和结构 |
|
||||||
|
|
||||||
|
|
||||||
|
## 贡献指南
|
||||||
|
|
||||||
|
欢迎通过以下方式参与项目改进:
|
||||||
|
1. 提交Issue报告问题
|
||||||
|
2. Fork仓库并提交Pull Request
|
||||||
|
3. 优化代码注释或文档
|
||||||
|
|
||||||
|
**开发团队**:
|
||||||
|
- 程序员:鲁豫 \<2085520973@qq.com>
|
||||||
|
- 代码审核:Xuekun Lu \<luxuekun@forling.cn>
|
||||||
|
|
||||||
|
## 学习资源
|
||||||
|
|
||||||
|
- [Tkinter官方文档](https://docs.python.org/3/library/tkinter.html)
|
||||||
|
- [Python异常处理指南](https://docs.python.org/3/tutorial/errors.html)
|
||||||
|
- [GUI设计最佳实践](https://learn.microsoft.com/zh-cn/windows/win32/uxguide/guidelines)
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
本项目基于 [MIT License](LICENSE) 开源
|
||||||
288
calculator.py
Normal file
288
calculator.py
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
"""
|
||||||
|
简易计算器GUI程序
|
||||||
|
[版本信息]
|
||||||
|
版本号 | 日期 | 作者 | 修改摘要
|
||||||
|
----------|------------|------------|------------------
|
||||||
|
v1.0.0 | 2025-04-19 | 鲁豫 | 初始版本,实现基本加减法功能
|
||||||
|
|
||||||
|
[作者信息]
|
||||||
|
开发团队:Python学习
|
||||||
|
程序员:鲁豫<2085520973@qq.com>
|
||||||
|
代码审核:Xuekun Lu
|
||||||
|
GitHub仓库:https://github.com/learn-python/calculator-gui
|
||||||
|
版权声明:本代码遵循MIT开源协议
|
||||||
|
|
||||||
|
[功能说明]
|
||||||
|
实现带图形界面的四则运算计算器,支持以下特性:
|
||||||
|
1. 基础运算:加减乘除
|
||||||
|
2. 连续运算功能
|
||||||
|
3. 错误处理机制
|
||||||
|
4. 历史记录显示(开发中)
|
||||||
|
|
||||||
|
代码结构说明:
|
||||||
|
1.全局状态:使用三个变量跟踪计算器状态
|
||||||
|
2.样式配置:集中管理颜色、字体等视觉元素
|
||||||
|
3.事件处理:5个函数处理不同按钮的点击逻辑
|
||||||
|
4.界面构建:分模块创建各个界面组件
|
||||||
|
5.布局管理:使用grid布局实现计算器按键矩阵
|
||||||
|
|
||||||
|
学习重点:
|
||||||
|
1.StringVar的使用:实现显示内容的动态更新
|
||||||
|
2.lambda表达式:用于传递参数的按钮命令绑定
|
||||||
|
3.全局状态管理:如何处理连续运算的中间状态
|
||||||
|
4.异常处理:保证程序在错误输入时不会崩溃
|
||||||
|
5.布局技巧:grid布局的跨列(rowspan)和跨行(columnspan)使用
|
||||||
|
|
||||||
|
测试建议:
|
||||||
|
1.测试乘法:5 × 3 = 15
|
||||||
|
2.测试除法:9 ÷ 3 = 3
|
||||||
|
3.测试除零:5 ÷ 0 → 显示"除零错误"
|
||||||
|
4.连续运算测试:2 + 3 = 5 → × 4 = 20
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 导入Tkinter图形界面库(Python标准库)
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
# ==================== 全局状态变量 ====================
|
||||||
|
# 这些变量用于跟踪计算器的当前状态
|
||||||
|
current_input = "" # 存储用户当前输入的数字(字符串形式,如"12.34")
|
||||||
|
first_operand = None # 存储第一个运算数字(当用户点击运算符时保存)
|
||||||
|
operator = None # 存储当前选择的运算符(+/-等)
|
||||||
|
|
||||||
|
# ==================== 界面样式常量配置 ====================
|
||||||
|
# 使用字典统一管理样式,方便后期修改和维护
|
||||||
|
COLORS = {
|
||||||
|
'operator': '#b1b2b2', # 运算符按钮背景色(浅灰色)
|
||||||
|
'number': '#eacda1', # 数字按钮背景色(米黄色)
|
||||||
|
'equal': '#eacda1' # 等号按钮背景色(与数字键相同)
|
||||||
|
}
|
||||||
|
|
||||||
|
FONT = {
|
||||||
|
'main': ('宋体', 20), # 显示屏字体(字体,字号)
|
||||||
|
'button': ('宋体', 16) # 按钮字体
|
||||||
|
}
|
||||||
|
|
||||||
|
LAYOUT = {
|
||||||
|
'pad': 4, # 按钮之间的水平间距(单位:像素)
|
||||||
|
'margin': 2 # 按钮之间的垂直间距
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 事件处理函数 ====================
|
||||||
|
# 以下函数用于响应按钮点击事件
|
||||||
|
|
||||||
|
def on_number_click(char):
|
||||||
|
"""处理数字和小数点按钮点击事件
|
||||||
|
参数:char - 按钮对应的字符(0-9 或 .)
|
||||||
|
"""
|
||||||
|
global current_input # 声明使用全局变量
|
||||||
|
|
||||||
|
# 处理小数点输入限制
|
||||||
|
if char == '.' and '.' in current_input:
|
||||||
|
return # 如果已包含小数点,不做任何操作
|
||||||
|
|
||||||
|
current_input += char # 将新字符追加到当前输入
|
||||||
|
result_var.set(current_input) # 更新显示屏内容
|
||||||
|
|
||||||
|
|
||||||
|
def on_operator_click(op):
|
||||||
|
"""处理运算符按钮点击事件(+/-/*//)
|
||||||
|
参数:op - 运算符符号(字符串)
|
||||||
|
"""
|
||||||
|
global first_operand, operator, current_input
|
||||||
|
|
||||||
|
if current_input: # 确保有输入值时才执行
|
||||||
|
first_operand = float(current_input) # 将当前输入转为浮点数存储
|
||||||
|
operator = op # 记录运算符
|
||||||
|
current_input = "" # 清空当前输入,准备接收第二个数字
|
||||||
|
result_var.set(op) # 在显示屏显示当前运算符
|
||||||
|
|
||||||
|
|
||||||
|
def calculate():
|
||||||
|
"""执行计算并显示结果"""
|
||||||
|
global current_input, first_operand, operator
|
||||||
|
|
||||||
|
# 有效性检查:确保三个要素都存在
|
||||||
|
if first_operand is None or operator is None or not current_input:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
second_operand = float(current_input) # 将当前输入转为浮点数
|
||||||
|
|
||||||
|
# 根据运算符执行计算(新增乘除运算)
|
||||||
|
if operator == '+':
|
||||||
|
result = first_operand + second_operand
|
||||||
|
elif operator == '-':
|
||||||
|
result = first_operand - second_operand
|
||||||
|
elif operator == '*':
|
||||||
|
result = first_operand * second_operand
|
||||||
|
elif operator == '/':
|
||||||
|
if second_operand == 0:
|
||||||
|
raise ZeroDivisionError
|
||||||
|
result = first_operand / second_operand
|
||||||
|
else:
|
||||||
|
return # 无效运算符
|
||||||
|
|
||||||
|
# 格式化显示结果:整数去零,小数保留10位
|
||||||
|
if result.is_integer():
|
||||||
|
current_input = str(int(result)) # 5.0 → 5
|
||||||
|
else:
|
||||||
|
# 去除末尾多余的零和小数点
|
||||||
|
formatted = "{:.10f}".format(result).rstrip('0').rstrip('.')
|
||||||
|
current_input = formatted if formatted else "0"
|
||||||
|
|
||||||
|
result_var.set(current_input) # 更新显示
|
||||||
|
|
||||||
|
# 保留计算结果作为下一次运算的第一个操作数
|
||||||
|
first_operand = float(current_input)
|
||||||
|
operator = None # 重置运算符需手动选择
|
||||||
|
|
||||||
|
except ZeroDivisionError:
|
||||||
|
result_var.set("除零错误")
|
||||||
|
# reset_calculator()
|
||||||
|
except Exception as e:
|
||||||
|
result_var.set("错误"+e.__cause__) # 显示错误提示
|
||||||
|
# reset_calculator() # 重置计算器
|
||||||
|
|
||||||
|
|
||||||
|
def reset_calculator():
|
||||||
|
"""重置所有状态到初始值"""
|
||||||
|
global current_input, first_operand, operator
|
||||||
|
current_input = ""
|
||||||
|
first_operand = None
|
||||||
|
operator = None
|
||||||
|
result_var.set('0') # 显示屏归零
|
||||||
|
|
||||||
|
|
||||||
|
def backspace():
|
||||||
|
"""删除最后一个输入的字符"""
|
||||||
|
global current_input
|
||||||
|
if current_input:
|
||||||
|
current_input = current_input[:-1] # 移除最后一个字符
|
||||||
|
result_var.set(current_input if current_input else '0') # 显示剩余内容或0
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 主窗口初始化 ====================
|
||||||
|
# 创建主窗口并设置基本属性
|
||||||
|
root = tk.Tk() # 创建Tkinter主窗口对象
|
||||||
|
root.title('简易计算器') # 窗口标题
|
||||||
|
root.geometry('295x280+100+100') # 窗口尺寸(宽x高)和初始位置(x+y)
|
||||||
|
root.attributes("-alpha", 0.9) # 设置窗口透明度(0.0完全透明-1.0不透明)
|
||||||
|
|
||||||
|
# ==================== 结果显示区域 ====================
|
||||||
|
# 使用StringVar实现动态更新显示内容
|
||||||
|
result_var = tk.StringVar(value='0') # 创建绑定到显示区域的变量
|
||||||
|
|
||||||
|
# 创建显示标签(显示屏)
|
||||||
|
display = tk.Label(
|
||||||
|
root,
|
||||||
|
textvariable=result_var, # 绑定动态变量
|
||||||
|
font=FONT['main'], # 使用主字体
|
||||||
|
height=2, # 高度(行数)
|
||||||
|
width=20, # 宽度(字符数)
|
||||||
|
justify=tk.LEFT, # 文本左对齐
|
||||||
|
anchor=tk.SE # 文本定位到右下角(东南角)
|
||||||
|
)
|
||||||
|
# 使用grid布局管理器定位,跨4列显示
|
||||||
|
display.grid(row=1, column=1, columnspan=4)
|
||||||
|
|
||||||
|
# ==================== 操作符按钮行 ====================
|
||||||
|
# 定义第一行操作符按钮的配置(清除、退格、除、乘)
|
||||||
|
operator_buttons = [
|
||||||
|
# 格式:(显示文本, 行号, 列号, 点击命令)
|
||||||
|
('c', 2, 1, reset_calculator), # 清除按钮
|
||||||
|
('←', 2, 2, backspace), # 退格按钮
|
||||||
|
('/', 2, 3, lambda: on_operator_click('/')), # 除法按钮
|
||||||
|
('×', 2, 4, lambda: on_operator_click('*')) # 乘法按钮
|
||||||
|
]
|
||||||
|
|
||||||
|
# 批量创建操作符按钮
|
||||||
|
for text, row, col, command in operator_buttons:
|
||||||
|
tk.Button(
|
||||||
|
root,
|
||||||
|
text=text,
|
||||||
|
width=5, # 按钮宽度(字符数)
|
||||||
|
font=FONT['button'], # 使用按钮字体
|
||||||
|
relief=tk.FLAT, # 扁平化按钮样式
|
||||||
|
bg=COLORS['operator'], # 设置背景色
|
||||||
|
command=command # 绑定点击事件处理函数
|
||||||
|
).grid(
|
||||||
|
row=row,
|
||||||
|
column=col,
|
||||||
|
padx=LAYOUT['pad'],
|
||||||
|
pady=LAYOUT['margin']
|
||||||
|
)
|
||||||
|
|
||||||
|
# ==================== 数字按钮布局 ====================
|
||||||
|
# 定义数字按钮的布局配置(使用嵌套元组)
|
||||||
|
button_configs = [
|
||||||
|
# 每行按钮配置(格式:(按钮1配置, 按钮2配置, ...))
|
||||||
|
# 第三行:7、8、9、减号
|
||||||
|
(('7', 3, 1), ('8', 3, 2), ('9', 3, 3), ('-', 3, 4, lambda: on_operator_click('-'))),
|
||||||
|
# 第四行:4、5、6、加号
|
||||||
|
(('4', 4, 1), ('5', 4, 2), ('6', 4, 3), ('+', 4, 4, lambda: on_operator_click('+'))),
|
||||||
|
# 第五行:1、2、3
|
||||||
|
(('1', 5, 1), ('2', 5, 2), ('3', 5, 3)),
|
||||||
|
# 第六行:0、小数点
|
||||||
|
(('0', 6, 1), ('.', 6, 3))
|
||||||
|
]
|
||||||
|
|
||||||
|
# 遍历配置创建数字按钮
|
||||||
|
for row_group in button_configs:
|
||||||
|
for config in row_group:
|
||||||
|
# 解析按钮配置
|
||||||
|
parts = list(config)
|
||||||
|
text, row, col = parts[0:3] # 前三个元素固定
|
||||||
|
|
||||||
|
# 确定点击命令:数字/小数点调用on_number_click,运算符调用on_operator_click
|
||||||
|
command = parts[3] if len(parts) > 3 else (lambda t=text: on_number_click(t))
|
||||||
|
|
||||||
|
# 创建按钮对象
|
||||||
|
btn = tk.Button(
|
||||||
|
root,
|
||||||
|
text=text,
|
||||||
|
width=5 if text != '0' else 12, # 0按钮特殊宽度
|
||||||
|
font=FONT['button'],
|
||||||
|
relief=tk.FLAT,
|
||||||
|
bg=COLORS['number'] if text in '1234567890.' else COLORS['operator'],
|
||||||
|
command=command # 绑定点击事件
|
||||||
|
)
|
||||||
|
|
||||||
|
# 布局按钮(0按钮需要跨列)
|
||||||
|
if text == '0':
|
||||||
|
btn.grid(
|
||||||
|
row=row,
|
||||||
|
column=col,
|
||||||
|
columnspan=2, # 跨2列
|
||||||
|
padx=LAYOUT['pad'],
|
||||||
|
pady=LAYOUT['margin']
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
btn.grid(
|
||||||
|
row=row,
|
||||||
|
column=col,
|
||||||
|
padx=LAYOUT['pad'],
|
||||||
|
pady=LAYOUT['margin']
|
||||||
|
)
|
||||||
|
|
||||||
|
# ==================== 等号按钮 ====================
|
||||||
|
# 创建特殊尺寸的等号按钮
|
||||||
|
tk.Button(
|
||||||
|
root,
|
||||||
|
text='=',
|
||||||
|
width=5, # 宽度(字符数)
|
||||||
|
height=3, # 高度(行数)
|
||||||
|
font=FONT['button'],
|
||||||
|
relief=tk.FLAT,
|
||||||
|
bg=COLORS['equal'], # 使用等号专用颜色
|
||||||
|
command=calculate # 绑定计算函数
|
||||||
|
).grid(
|
||||||
|
row=5,
|
||||||
|
column=4,
|
||||||
|
rowspan=2, # 跨5-6两行
|
||||||
|
padx=LAYOUT['pad'],
|
||||||
|
pady=LAYOUT['margin']
|
||||||
|
)
|
||||||
|
|
||||||
|
# ==================== 启动程序 ====================
|
||||||
|
root.mainloop() # 进入Tkinter事件循环,等待用户操作
|
||||||
BIN
screenshot.png
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Loading…
x
Reference in New Issue
Block a user