""" 简易计算器GUI程序 [Version information] Version | Date | Author | Summary ----------|------------|------------|------------------ v1.0.0 | 2025-04-15 | Lucy | 初始版本,实现基本加减乘除法功能 [Author information] Teams:Python学习 Developer:Lucy <2085520973@qq.com> Code Reviewer:Xuekun Lu Git Repo:https://git.forling.cn/luxuekun/calculator.git License: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事件循环,等待用户操作