calculator/calculator.py
2025-04-19 23:51:48 +08:00

290 lines
9.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
简易计算器GUI程序
[Version information]
Version | Date | Author | Summary
----------|------------|------------|------------------
v1.0.0 | 2025-04-15 | Lucy | 初始版本,实现基本加减乘除法功能
[Author information]
TeamsPython学习
DeveloperLucy <2085520973@qq.com>
Code ReviewerXuekun Lu <luxuekun@forling.cn>
Git Repohttps://git.forling.cn/luxuekun/calculator.git
LicenseMIT
[功能说明]
实现带图形界面的四则运算计算器,支持以下特性:
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事件循环等待用户操作