手把手教你用 Python 做计算器!从命令行到图形界面(附完整 GUI 源码)

计算器是日常生活和工作中常用的工具,也是学习编程的经典入门项目。本文将使用 Python 实现一个功能完备的计算器,从基础的命令行版本逐步升级到具有现代界面的图形化应用程序。通过这个项目,你将学习 Python 编程的核心概念,包括变量、数据类型、控制结构、函数、模块以及图形界面开发。

一、计算器基本原理与流程

计算器的基本功能是接收用户输入的数学表达式,计算其结果并显示出来。我们可以从最简单的命令行版本开始实现:

def calculate(expression):
    """计算数学表达式的值"""
    try:
        # 使用 Python 的 eval() 函数计算表达式
        result = eval(expression)
        return result
    except Exception as e:
        print(f"错误: {e}")
        return None

def simple_calculator():
    """简易计算器主函数"""
    print("欢迎使用简易计算器!")
    print("支持基本的数学运算,如 +, -, *, /, ** 等")
    print("输入 'q' 退出计算器")
    
    while True:
        expression = input("请输入数学表达式: ")
        
        if expression.lower() == 'q':
            print("感谢使用计算器,再见!")
            break
        
        result = calculate(expression)
        if result is not None:
            print(f"计算结果: {result}")

# 启动计算器
simple_calculator()

在这里插入图片描述

知识点解析

  1. eval() 函数:Python 内置函数,用于执行字符串表达式并返回结果
  2. 异常处理:使用 try-except 捕获并处理计算过程中可能出现的错误
  3. 循环结构:使用 while True 创建无限循环,直到用户输入 ‘q’ 退出
  4. 用户交互:使用 input() 获取用户输入,print() 输出结果

二、计算器功能扩展

我们可以对基础版本进行扩展,增加以下功能:

  1. 历史记录:保存用户的计算历史
  2. 内存功能:支持将结果存入内存或从内存中读取
  3. 更丰富的运算:支持三角函数、对数函数等高级运算
  4. 表达式验证:在计算前验证表达式的合法性

下面是扩展后的代码:

import math
import re

class Calculator:
    def __init__(self):
        self.memory = 0  # 内存值
        self.history = []  # 历史记录
        self.functions = {
            'sin': math.sin,
            'cos': math.cos,
            'tan': math.tan,
            'sqrt': math.sqrt,
            'log': math.log,
            'exp': math.exp
        }
    
    def calculate(self, expression):
        """计算数学表达式的值"""
        # 处理内存操作
        expression = expression.replace('M+', f'+{self.memory}')
        expression = expression.replace('M-', f'-{self.memory}')
        expression = expression.replace('MR', str(self.memory))
        
        # 替换函数调用
        for func_name, func in self.functions.items():
            pattern = rf'{func_name}\(([^)]+)\)'
            while re.search(pattern, expression):
                match = re.search(pattern, expression)
                arg = match.group(1)
                try:
                    result = func(float(arg))
                    expression = expression.replace(match.group(0), str(result))
                except Exception as e:
                    return f"错误: 函数 {func_name} 参数错误"
        
        try:
            # 计算表达式
            result = eval(expression)
            
            # 更新历史记录
            self.history.append(f"{expression} = {result}")
            
            return result
        except ZeroDivisionError:
            return "错误: 除数不能为零"
        except Exception as e:
            return f"错误: {e}"
    
    def show_history(self):
        """显示计算历史"""
        if not self.history:
            print("暂无计算历史")
            return
        
        print("\n=== 计算历史 ===")
        for i, entry in enumerate(self.history, 1):
            print(f"{i}. {entry}")
    
    def clear_history(self):
        """清除计算历史"""
        self.history = []
        print("计算历史已清除")
    
    def set_memory(self, value):
        """设置内存值"""
        try:
            self.memory = float(value)
            print(f"内存已设置为: {self.memory}")
        except ValueError:
            print("错误: 无效的内存值")
    
    def clear_memory(self):
        """清除内存值"""
        self.memory = 0
        print("内存已清除")

def advanced_calculator():
    """高级计算器主函数"""
    calc = Calculator()
    
    print("欢迎使用高级计算器!")
    print("支持基本运算、函数计算、内存功能")
    print("支持的函数: sin, cos, tan, sqrt, log, exp")
    print("内存操作: M+ (加内存), M- (减内存), MR (读内存)")
    print("输入 'h' 查看历史记录, 'c' 清除历史, 'm' 设置内存")
    print("输入 'mc' 清除内存, 'q' 退出计算器")
    
    while True:
        expression = input("请输入数学表达式: ")
        
        if expression.lower() == 'q':
            print("感谢使用计算器,再见!")
            break
        elif expression.lower() == 'h':
            calc.show_history()
        elif expression.lower() == 'c':
            calc.clear_history()
        elif expression.lower() == 'm':
            value = input("请输入内存值: ")
            calc.set_memory(value)
        elif expression.lower() == 'mc':
            calc.clear_memory()
        else:
            result = calc.calculate(expression)
            print(f"计算结果: {result}")

# 启动计算器
advanced_calculator()

在这里插入图片描述

知识点解析

  1. 类的设计:使用 Calculator 类封装计算器的所有功能
  2. 正则表达式:使用 re 模块处理函数调用和内存操作的替换
  3. 数学函数:使用 math 模块提供的各种数学函数
  4. 数据结构:使用列表保存计算历史,使用变量保存内存值
  5. 模块化设计:将不同功能封装为独立的方法,提高代码的可维护性

三、图形界面实现

使用 Tkinter 库创建一个图形界面版本的计算器:

import tkinter as tk
from tkinter import ttk
import math
import re

class CalculatorGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("科学计算器")
        self.root.geometry("400x550")
        self.root.resizable(False, False)
        self.root.configure(bg="#f0f0f0")
        
        # 设置中文字体
        self.font = ("SimHei", 12)
        
        # 计算器逻辑
        self.memory = 0
        self.history = []
        self.current_expression = ""
        self.last_result = None
        
        # 创建界面
        self.create_widgets()
    
    def create_widgets(self):
        """创建计算器界面"""
        # 历史记录按钮
        history_frame = tk.Frame(self.root, bg="#f0f0f0")
        history_frame.pack(pady=5, fill=tk.X, padx=10)
        
        history_button = tk.Button(history_frame, text="历史记录", font=self.font, 
                                  command=self.show_history, bg="#2196F3", fg="white")
        history_button.pack(side=tk.RIGHT, padx=5)
        
        # 显示屏
        display_frame = tk.Frame(self.root, bg="#f0f0f0")
        display_frame.pack(pady=10, fill=tk.X, padx=10)
        
        self.expression_var = tk.StringVar()
        self.expression_var.set("")
        
        self.result_var = tk.StringVar()
        self.result_var.set("0")
        
        expression_label = tk.Label(display_frame, textvariable=self.expression_var, 
                                   font=("SimHei", 14), bg="white", anchor=tk.E, padx=10, pady=5)
        expression_label.pack(fill=tk.X)
        
        result_label = tk.Label(display_frame, textvariable=self.result_var, 
                               font=("SimHei", 24, "bold"), bg="white", anchor=tk.E, padx=10, pady=5)
        result_label.pack(fill=tk.X)
        
        # 按钮框架
        buttons_frame = tk.Frame(self.root, bg="#f0f0f0")
        buttons_frame.pack(pady=10, fill=tk.BOTH, expand=True, padx=10)
        
        # 按钮布局
        buttons = [
            ['7', '8', '9', '/', 'C'],
            ['4', '5', '6', '*', 'CE'],
            ['1', '2', '3', '-', '√'],
            ['0', '.', '=', '+', '^'],
            ['(', ')', 'M+', 'M-', 'MR']
        ]
        
        for i, row in enumerate(buttons):
            for j, text in enumerate(row):
                button = tk.Button(buttons_frame, text=text, font=self.font,
                                  width=7, height=2, bg="#e0e0e0",
                                  command=lambda txt=text: self.button_click(txt))
                button.grid(row=i, column=j, padx=2, pady=2, sticky="nsew")
        
        # 配置网格权重,使按钮均匀分布
        for i in range(len(buttons)):
            buttons_frame.grid_rowconfigure(i, weight=1)
        for j in range(len(buttons[0])):
            buttons_frame.grid_columnconfigure(j, weight=1)
    
    def button_click(self, text):
        """处理按钮点击事件"""
        if text == '=':
            self.calculate()
        elif text == 'C':
            self.current_expression = ""
            self.update_display()
        elif text == 'CE':
            # 删除最后一个字符
            self.current_expression = self.current_expression[:-1]
            self.update_display()
        elif text == '√':
            self.current_expression += "sqrt("
            self.update_display()
        elif text == '^':
            self.current_expression += "**"
            self.update_display()
        elif text == 'M+':
            self.current_expression += f"+{self.memory}"
            self.update_display()
        elif text == 'M-':
            self.current_expression += f"-{self.memory}"
            self.update_display()
        elif text == 'MR':
            self.current_expression += str(self.memory)
            self.update_display()
        else:
            self.current_expression += text
            self.update_display()
    
    def update_display(self):
        """更新显示屏"""
        self.expression_var.set(self.current_expression)
        
        # 如果表达式为空,显示0
        if not self.current_expression:
            self.result_var.set("0")
    
    def calculate(self):
        """计算表达式结果"""
        if not self.current_expression:
            return
        
        expression = self.current_expression
        
        # 替换函数调用
        pattern = r'sqrt\(([^)]+)\)'
        while re.search(pattern, expression):
            match = re.search(pattern, expression)
            arg = match.group(1)
            expression = expression.replace(match.group(0), f"math.sqrt({arg})")
        
        # 替换幂运算
        expression = expression.replace('^', '**')
        
        try:
            # 计算表达式
            result = eval(expression)
            
            # 更新历史记录
            self.history.append(f"{self.current_expression} = {result}")
            
            # 更新显示
            self.result_var.set(str(result))
            self.last_result = result
            
            # 如果用户想继续计算,使用结果作为新表达式的开始
            self.current_expression = str(result)
            
        except ZeroDivisionError:
            self.result_var.set("错误: 除数不能为零")
        except Exception as e:
            self.result_var.set(f"错误: {str(e)}")
    
    def show_history(self):
        """显示历史记录"""
        if not self.history:
            tk.messagebox.showinfo("历史记录", "暂无计算历史")
            return
        
        # 创建历史记录窗口
        history_window = tk.Toplevel(self.root)
        history_window.title("计算历史")
        history_window.geometry("400x300")
        history_window.resizable(False, False)
        history_window.configure(bg="#f0f0f0")
        history_window.transient(self.root)  # 使窗口成为主窗口的子窗口
        
        # 创建历史记录列表
        history_text = tk.Text(history_window, font=self.font, bg="white", wrap=tk.WORD)
        history_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 插入历史记录
        for i, entry in enumerate(self.history, 1):
            history_text.insert(tk.END, f"{i}. {entry}\n\n")
        
        # 使文本框只读
        history_text.config(state=tk.DISABLED)
        
        # 关闭按钮
        close_button = tk.Button(history_window, text="关闭", font=self.font,
                                command=history_window.destroy, bg="#f44336", fg="white")
        close_button.pack(pady=10)

# 启动计算器
if __name__ == "__main__":
    root = tk.Tk()
    app = CalculatorGUI(root)
    root.mainloop()

在这里插入图片描述

知识点解析

  1. Tkinter 基础:使用 Tkinter 创建窗口、标签、按钮等界面元素
  2. 事件处理:通过绑定按钮点击事件触发相应的函数
  3. 界面布局:使用 grid() 方法进行网格布局,实现计算器按钮的排列
  4. 对话框:创建模态对话框用于显示计算历史
  5. 表达式解析:处理特殊函数(如平方根)和操作符(如幂运算)的解析

四、计算器优化与扩展

我们可以进一步优化和扩展计算器,例如:

  1. 添加更多功能:支持三角函数、对数函数等更多数学函数
  2. 美化界面:使用更现代的UI设计,添加动画和过渡效果
  3. 支持键盘输入:允许用户使用键盘输入表达式
  4. 保存历史记录:将历史记录保存到文件中,实现持久化存储

下面是一个添加更多功能的示例:

# 在CalculatorGUI类中添加以下代码
def create_widgets(self):
    # ... 原有代码 ...
    
    # 第二行按钮(函数按钮)
    function_buttons = ['sin', 'cos', 'tan', 'log', 'exp']
    
    function_frame = tk.Frame(self.root, bg="#f0f0f0")
    function_frame.pack(pady=5, fill=tk.X, padx=10)
    
    for i, text in enumerate(function_buttons):
        button = tk.Button(function_frame, text=text, font=self.font,
                          width=7, height=1, bg="#d0d0d0",
                          command=lambda txt=text: self.button_click(txt))
        button.pack(side=tk.LEFT, padx=2, pady=2, fill=tk.BOTH, expand=True)
    
    # ... 原有代码 ...

def button_click(self, text):
    # ... 原有代码 ...
    elif text in ['sin', 'cos', 'tan', 'log', 'exp']:
        self.current_expression += f"{text}("
        self.update_display()
    # ... 原有代码 ...

def calculate(self):
    # ... 原有代码 ...
    
    # 替换更多函数调用
    for func in ['sin', 'cos', 'tan', 'log', 'exp']:
        pattern = rf'{func}\(([^)]+)\)'
        while re.search(pattern, expression):
            match = re.search(pattern, expression)
            arg = match.group(1)
            expression = expression.replace(match.group(0), f"math.{func}({arg})")
    
    # ... 原有代码 ...

总结

通过这个计算器项目,我们学习了 Python 编程的多个方面:

  1. 基础语法:变量、数据类型、控制结构、函数等
  2. 面向对象编程:使用类和对象组织代码,提高代码的可维护性
  3. 模块化设计:将不同功能封装为独立的模块和方法
  4. 图形界面开发:使用 Tkinter 创建交互式应用程序
  5. 用户交互与体验:设计友好的界面和流畅的用户体验

这个项目不仅帮助你掌握了 Python 编程的基础知识,还为你开发更复杂的应用程序打下了坚实的基础。建议你继续扩展这个计算器,添加更多功能,进一步提升自己的编程技能!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值