python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python tkinter计算器

基于Python的tkinter库开发一个计算器的完整代码

作者:搏博

Python是一种非常适合快速开发的编程语言,它有着丰富的库来支持图形用户界面(GUI)的开发,在本教程中,我们将使用tkinter库来创建一个简单计算器,tkinter是Python的标准GUI库,它是跨平台的,并且内置于大多数Python安装中,需要的朋友可以参考下

一、功能需求        

我们希望实现的这个计算器应用程序,具有以下特点:

1.功能齐全:

2.用户界面友好:

3.使用说明:

二、完整代码以及运行效果

1.完整代码

将以下代码,复制到开发工具中,通过CMD,这个应用程序可以直接运行,无需额外安装库。如需扩展功能,可以在代码中添加更多的按钮和对应的计算方法。

import tkinter as tk
from tkinter import font
import math
import re

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("高级计算器")
        self.root.geometry("400x600")
        self.root.resizable(False, False)
        self.root.configure(bg="#f0f0f0")
        
        # 设置字体
        self.display_font = font.Font(family="SimHei", size=24)
        self.button_font = font.Font(family="SimHei", size=14)
        
        # 计算变量
        self.current_expression = ""
        self.last_result = ""
        self.is_new_calculation = True
        
        # 创建界面
        self._create_display()
        self._create_buttons()
        
        # 绑定键盘事件
        self.root.bind("<Key>", self._handle_key_event)
    
    def _create_display(self):
        # 历史记录显示
        self.history_frame = tk.Frame(self.root, bg="#f0f0f0", height=50)
        self.history_frame.pack(fill=tk.X, padx=10, pady=(10, 0))
        self.history_frame.pack_propagate(0)
        
        self.history_label = tk.Label(
            self.history_frame, 
            text="", 
            bg="#f0f0f0", 
            fg="#888", 
            font=self.display_font,
            anchor=tk.E
        )
        self.history_label.pack(fill=tk.BOTH, padx=5)
        
        # 当前表达式显示
        self.display_frame = tk.Frame(self.root, bg="#f0f0f0", height=80)
        self.display_frame.pack(fill=tk.X, padx=10, pady=5)
        self.display_frame.pack_propagate(0)
        
        self.display = tk.Entry(
            self.display_frame, 
            font=self.display_font, 
            bg="white", 
            fg="black", 
            justify=tk.RIGHT,
            bd=5,
            relief=tk.SUNKEN
        )
        self.display.pack(fill=tk.BOTH, padx=5, pady=5)
        self.display.insert(0, "0")
        self.display.configure(state="readonly")
    
    def _create_buttons(self):
        button_frame = tk.Frame(self.root, bg="#f0f0f0")
        button_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 定义按钮布局
        buttons = [
            ("7", 1, 0), ("8", 1, 1), ("9", 1, 2), ("/", 1, 3), ("C", 1, 4),
            ("4", 2, 0), ("5", 2, 1), ("6", 2, 2), ("*", 2, 3), ("⌫", 2, 4),
            ("1", 3, 0), ("2", 3, 1), ("3", 3, 2), ("-", 3, 3), ("(", 3, 4),
            ("0", 4, 0), (".", 4, 1), ("=", 4, 2), ("+", 4, 3), (")", 4, 4),
            ("%", 5, 0), ("√", 5, 1), ("^", 5, 2), ("π", 5, 3), ("sin", 5, 4),
            ("cos", 6, 0), ("tan", 6, 1), ("ln", 6, 2), ("log", 6, 3), ("1/x", 6, 4)
        ]
        
        # 创建按钮
        for button_data in buttons:
            text, row, col = button_data
            
            # 设置按钮样式
            if text == "=":
                bg_color = "#4CAF50"
                fg_color = "white"
            elif text == "C" or text == "⌫":
                bg_color = "#f44336"
                fg_color = "white"
            elif col == 3 or col == 4:
                bg_color = "#2196F3"
                fg_color = "white"
            else:
                bg_color = "#e0e0e0"
                fg_color = "black"
            
            # 创建按钮
            button = tk.Button(
                button_frame,
                text=text,
                font=self.button_font,
                bg=bg_color,
                fg=fg_color,
                relief=tk.RAISED,
                bd=3,
                padx=10,
                pady=10,
                command=lambda txt=text: self._button_click(txt)
            )
            
            # 设置按钮网格
            button.grid(row=row, column=col, padx=5, pady=5, sticky="nsew")
        
        # 设置网格权重,使按钮均匀分布
        for i in range(7):
            button_frame.grid_rowconfigure(i, weight=1)
        for i in range(5):
            button_frame.grid_columnconfigure(i, weight=1)
    
    def _button_click(self, text):
        # 处理按钮点击事件
        if text == "C":
            self._clear_all()
        elif text == "⌫":
            self._backspace()
        elif text == "=":
            self._calculate()
        elif text == "π":
            self._append_value(str(math.pi))
        elif text == "√":
            self._calculate_sqrt()
        elif text == "^":
            self._append_value("**")
        elif text == "sin":
            self._calculate_trig("sin")
        elif text == "cos":
            self._calculate_trig("cos")
        elif text == "tan":
            self._calculate_trig("tan")
        elif text == "ln":
            self._calculate_ln()
        elif text == "log":
            self._calculate_log()
        elif text == "1/x":
            self._calculate_reciprocal()
        elif text == "%":
            self._calculate_percentage()
        else:
            self._append_value(text)
    
    def _handle_key_event(self, event):
        # 处理键盘事件
        key = event.char
        
        if key.isdigit() or key in "+-*/().":
            self._append_value(key)
        elif key == "\r" or key == "=":
            self._calculate()
        elif key == "\x08":  # Backspace
            self._backspace()
        elif key.lower() == "c":
            self._clear_all()
    
    def _append_value(self, value):
        # 追加值到当前表达式
        if self.is_new_calculation:
            self.current_expression = ""
            self.is_new_calculation = False
        
        if self.current_expression == "0" and value.isdigit():
            self.current_expression = value
        else:
            self.current_expression += value
        
        self._update_display()
    
    def _clear_all(self):
        # 清除所有内容
        self.current_expression = ""
        self.history_label.config(text="")
        self.is_new_calculation = True
        self._update_display()
    
    def _backspace(self):
        # 删除最后一个字符
        if not self.is_new_calculation and self.current_expression:
            self.current_expression = self.current_expression[:-1]
            self._update_display()
    
    def _update_display(self):
        # 更新显示内容
        self.display.configure(state="normal")
        self.display.delete(0, tk.END)
        
        # 格式化显示内容
        display_text = self.current_expression
        
        # 检查表达式长度,如果太长则缩小字体
        if len(display_text) > 15:
            self.display_font.configure(size=18)
        else:
            self.display_font.configure(size=24)
        
        self.display.insert(0, display_text)
        self.display.configure(state="readonly")
    
    def _calculate(self):
        # 计算表达式结果
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            # 替换π和e
            expression = self.current_expression
            expression = re.sub(r'π', str(math.pi), expression)
            expression = re.sub(r'e', str(math.e), expression)
            
            # 计算结果
            result = eval(expression)
            
            # 格式化结果
            if isinstance(result, float):
                # 处理浮点数精度
                if result.is_integer():
                    result = int(result)
                else:
                    result = round(result, 10)
            
            # 更新历史记录
            self.history_label.config(text=f"{self.current_expression} = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_sqrt(self):
        # 计算平方根
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            if value < 0:
                raise ValueError("平方根不能为负数")
            
            result = math.sqrt(value)
            
            # 更新历史记录
            self.history_label.config(text=f"√{self.current_expression} = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_trig(self, func):
        # 计算三角函数
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            # 假设输入是角度,转换为弧度
            radians = math.radians(value)
            
            if func == "sin":
                result = math.sin(radians)
            elif func == "cos":
                result = math.cos(radians)
            elif func == "tan":
                result = math.tan(radians)
            else:
                result = "错误"
            
            # 更新历史记录
            self.history_label.config(text=f"{func}({self.current_expression}°) = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_ln(self):
        # 计算自然对数
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            if value <= 0:
                raise ValueError("对数的真数必须大于0")
            
            result = math.log(value)
            
            # 更新历史记录
            self.history_label.config(text=f"ln({self.current_expression}) = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_log(self):
        # 计算常用对数
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            if value <= 0:
                raise ValueError("对数的真数必须大于0")
            
            result = math.log10(value)
            
            # 更新历史记录
            self.history_label.config(text=f"log({self.current_expression}) = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_reciprocal(self):
        # 计算倒数
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            if value == 0:
                raise ZeroDivisionError("不能除以零")
            
            result = 1 / value
            
            # 更新历史记录
            self.history_label.config(text=f"1/{self.current_expression} = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True
    
    def _calculate_percentage(self):
        # 计算百分比
        if not self.current_expression or self.is_new_calculation:
            return
        
        try:
            value = float(self.current_expression)
            result = value / 100
            
            # 更新历史记录
            self.history_label.config(text=f"{self.current_expression}% = {result}")
            
            # 更新当前表达式
            self.current_expression = str(result)
            self.last_result = str(result)
            self.is_new_calculation = True
            
            self._update_display()
            
        except Exception as e:
            self.display.configure(state="normal")
            self.display.delete(0, tk.END)
            self.display.insert(0, "错误")
            self.display.configure(state="readonly")
            self.current_expression = ""
            self.is_new_calculation = True

if __name__ == "__main__":
    root = tk.Tk()
    app = Calculator(root)
    root.mainloop()    

2.运行效果

打开CMD,写上“py+空格”,将文件拖入,回车运行即可。

三、代码详细解析

这个计算器应用程序基于 Python 的 tkinter 库开发,具有友好的用户界面和丰富的计算功能。下面我将从整体架构到具体功能逐步解析代码:

1.整体架构

代码采用面向对象的方式组织,核心是Calculator类,它负责:

2.初始化与界面设置

Calculator类中有一个初始化方法__init__(),实例化了一个GUI对象,并设置标题、窗体大小、是否可放大缩小,以及背景颜色配置。

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("高级计算器")
        self.root.geometry("400x600")
        self.root.resizable(False, False)
        self.root.configure(bg="#f0f0f0")
        
        # 设置字体
        self.display_font = font.Font(family="SimHei", size=24)
        self.button_font = font.Font(family="SimHei", size=14)
        
        # 计算变量
        self.current_expression = ""
        self.last_result = ""
        self.is_new_calculation = True
        
        # 创建界面
        self._create_display()
        self._create_buttons()
        
        # 绑定键盘事件
        self.root.bind("<Key>", self._handle_key_event)

代码说明:

3.显示区域设计

包括当前输入的内容和上一次的计算记录,上一次的计算记录放在输入框上面。

def _create_display(self):
    # 历史记录显示
    self.history_frame = tk.Frame(self.root, bg="#f0f0f0", height=50)
    self.history_frame.pack(fill=tk.X, padx=10, pady=(10, 0))
    self.history_frame.pack_propagate(0)
    
    self.history_label = tk.Label(
        self.history_frame, 
        text="", 
        bg="#f0f0f0", 
        fg="#888", 
        font=self.display_font,
        anchor=tk.E
    )
    self.history_label.pack(fill=tk.BOTH, padx=5)
    
    # 当前表达式显示
    self.display_frame = tk.Frame(self.root, bg="#f0f0f0", height=80)
    self.display_frame.pack(fill=tk.X, padx=10, pady=5)
    self.display_frame.pack_propagate(0)
    
    self.display = tk.Entry(
        self.display_frame, 
        font=self.display_font, 
        bg="white", 
        fg="black", 
        justify=tk.RIGHT,
        bd=5,
        relief=tk.SUNKEN
    )
    self.display.pack(fill=tk.BOTH, padx=5, pady=5)
    self.display.insert(0, "0")
    self.display.configure(state="readonly")

代码说明:

4.按钮布局与设计

所有的按钮用列表保存。

def _create_buttons(self):
    button_frame = tk.Frame(self.root, bg="#f0f0f0")
    button_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
    
    # 定义按钮布局
    buttons = [
        ("7", 1, 0), ("8", 1, 1), ("9", 1, 2), ("/", 1, 3), ("C", 1, 4),
        ("4", 2, 0), ("5", 2, 1), ("6", 2, 2), ("*", 2, 3), ("⌫", 2, 4),
        ("1", 3, 0), ("2", 3, 1), ("3", 3, 2), ("-", 3, 3), ("(", 3, 4),
        ("0", 4, 0), (".", 4, 1), ("=", 4, 2), ("+", 4, 3), (")", 4, 4),
        ("%", 5, 0), ("√", 5, 1), ("^", 5, 2), ("π", 5, 3), ("sin", 5, 4),
        ("cos", 6, 0), ("tan", 6, 1), ("ln", 6, 2), ("log", 6, 3), ("1/x", 6, 4)
    ]
    
    # 创建按钮
    for button_data in buttons:
        text, row, col = button_data
        
        # 设置按钮样式
        if text == "=":
            bg_color = "#4CAF50"  # 绿色
            fg_color = "white"
        elif text == "C" or text == "⌫":
            bg_color = "#f44336"  # 红色
            fg_color = "white"
        elif col == 3 or col == 4:
            bg_color = "#2196F3"  # 蓝色
            fg_color = "white"
        else:
            bg_color = "#e0e0e0"  # 灰色
            fg_color = "black"
            
        # 创建按钮并绑定事件
        ...

代码说明:

5.核心计算功能

def _calculate(self):
    # 计算表达式结果
    if not self.current_expression or self.is_new_calculation:
        return
    
    try:
        # 替换π和e
        expression = self.current_expression
        expression = re.sub(r'π', str(math.pi), expression)
        expression = re.sub(r'e', str(math.e), expression)
        
        # 计算结果
        result = eval(expression)
        
        # 格式化结果
        if isinstance(result, float):
            if result.is_integer():
                result = int(result)
            else:
                result = round(result, 10)
        
        # 更新历史记录和显示
        ...
        
    except Exception as e:
        self.display.configure(state="normal")
        self.display.delete(0, tk.END)
        self.display.insert(0, "错误")
        self.display.configure(state="readonly")
        self.current_expression = ""
        self.is_new_calculation = True

代码说明:

6.高级数学功能

计算器能实现多种基本的数学运算。

def _calculate_sqrt(self):
    # 计算平方根
    if not self.current_expression or self.is_new_calculation:
        return
    
    try:
        value = float(self.current_expression)
        if value < 0:
            raise ValueError("平方根不能为负数")
        
        result = math.sqrt(value)
        
        # 更新历史记录和显示
        ...
        
    except Exception as e:
        self.display.configure(state="normal")
        self.display.delete(0, tk.END)
        self.display.insert(0, "错误")
        self.display.configure(state="readonly")
        self.current_expression = ""
        self.is_new_calculation = True

def _calculate_trig(self, func):
    # 计算三角函数
    if not self.current_expression or self.is_new_calculation:
        return
    
    try:
        value = float(self.current_expression)
        # 假设输入是角度,转换为弧度
        radians = math.radians(value)
        
        if func == "sin":
            result = math.sin(radians)
        elif func == "cos":
            result = math.cos(radians)
        elif func == "tan":
            result = math.tan(radians)
        else:
            result = "错误"
        
        # 更新历史记录和显示
        ...
        
    except Exception as e:
        self.display.configure(state="normal")
        self.display.delete(0, tk.END)
        self.display.insert(0, "错误")
        self.display.configure(state="readonly")
        self.current_expression = ""
        self.is_new_calculation = True

代码说明:

7.用户输入处理

def _button_click(self, text):
    # 处理按钮点击事件
    if text == "C":
        self._clear_all()
    elif text == "⌫":
        self._backspace()
    elif text == "=":
        self._calculate()
    elif text == "π":
        self._append_value(str(math.pi))
    elif text == "√":
        self._calculate_sqrt()
    elif text == "^":
        self._append_value("**")
    elif text in ["sin", "cos", "tan"]:
        self._calculate_trig(text)
    elif text == "ln":
        self._calculate_ln()
    elif text == "log":
        self._calculate_log()
    elif text == "1/x":
        self._calculate_reciprocal()
    elif text == "%":
        self._calculate_percentage()
    else:
        self._append_value(text)

def _handle_key_event(self, event):
    # 处理键盘事件
    key = event.char
    
    if key.isdigit() or key in "+-*/().":
        self._append_value(key)
    elif key == "\r" or key == "=":
        self._calculate()
    elif key == "\x08":  # Backspace
        self._backspace()
    elif key.lower() == "c":
        self._clear_all()

代码说明:

8.动态字体调整

输入框长度是有限的,有时希望尽量能看清所有输入的字符,所以做了动态字体调整。

def _update_display(self):
    # 更新显示内容
    self.display.configure(state="normal")
    self.display.delete(0, tk.END)
    
    # 格式化显示内容
    display_text = self.current_expression
    
    # 检查表达式长度,如果太长则缩小字体
    if len(display_text) > 15:
        self.display_font.configure(size=18)
    else:
        self.display_font.configure(size=24)
    
    self.display.insert(0, display_text)
    self.display.configure(state="readonly")

代码说明:

9.程序入口

if __name__ == "__main__":
    root = tk.Tk()
    app = Calculator(root)
    root.mainloop()

代码说明:

10.功能扩展建议

这个计算器已经具备了基本和高级的计算功能,界面友好且易于使用。通过进一步扩展,可以使其成为更加强大的科学计算器。

以上就是基于Python的tkinter库开发一个计算器的完整代码的详细内容,更多关于Python tkinter计算器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文