【经验分享】使用Python的图形库创建一个好看实用的计算器,附完整项目代码

2024-08-02 07:56:55 浏览数 (3)

项目图片展示

这篇博客将详细介绍如何使用Python的ttkbootstrap模块创建一个功能齐全且美观的计算器应用程序。项目功能包括基本的算术运算、历史记录查看、主题切换、窗口大小调整等。本文将从项目环境设置、代码实现、功能介绍等方面进行详细讲解。

1. 环境准备

在开始之前,请确保您的开发环境中已经安装了以下工具和库:

  • Python 3.x
  • ttkbootstrap
  • Tkinter(Python标准库自带)

安装ttkbootstrap库:

代码语言:javascript复制
pip install ttkbootstrap
2. 项目结构

项目的主要文件包括:

  • calculator.py:主程序文件,包含计算器的所有逻辑和UI设计。
3. 代码实现

接下来是详细的代码实现及其功能说明。

3.1 导入库

首先,我们需要导入所需的库和模块。

代码语言:javascript复制
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import StringVar, Text, Menu, Toplevel, messagebox, simpledialog
import datetime
3.2 创建主类

我们将所有的功能和UI组件封装在一个类中。

代码语言:javascript复制
class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("计算器")
        self.root.geometry("320x420")
        self.root.resizable(False, False)
        
        self.entry_var = StringVar()
        self.history = []

        self.create_menu()
        self.create_widgets()
3.3 创建菜单

菜单栏包含历史记录查看、日期查看、开发者信息查看、修改主题和修改窗口大小等功能。

代码语言:javascript复制
def create_menu(self):
    menubar = Menu(self.root)

    # 历史记录菜单
    history_menu = Menu(menubar, tearoff=0)
    history_menu.add_command(label="查看历史记录", command=self.show_history)
    menubar.add_cascade(label="历史记录", menu=history_menu)

    # 查看菜单
    view_menu = Menu(menubar, tearoff=0)
    view_menu.add_command(label="查看日期", command=self.show_date)
    view_menu.add_command(label="查看开发者", command=self.show_developer)
    menubar.add_cascade(label="查看", menu=view_menu)

    # 修改菜单
    edit_menu = Menu(menubar, tearoff=0)

    # 修改主题子菜单
    theme_menu = Menu(edit_menu, tearoff=0)
    style = ttk.Style()
    theme_names = style.theme_names()  # 以列表的形式返回多个主题名
    for theme_name in theme_names:
        theme_menu.add_command(label=theme_name, command=lambda t=theme_name: self.change_theme(t))
    edit_menu.add_cascade(label="修改主题", menu=theme_menu)

    # 修改窗口大小功能
    edit_menu.add_command(label="修改窗口大小", command=self.change_window_size)
    menubar.add_cascade(label="修改", menu=edit_menu)

    self.root.config(menu=menubar)
3.4 修改主题和窗口大小的功能

添加修改主题和修改窗口大小的具体实现。

代码语言:javascript复制
def change_theme(self, theme_name):
    style = ttk.Style()
    style.theme_use(theme_name)

def change_window_size(self):
    new_width = simpledialog.askinteger("输入宽度", "请输入新的窗口宽度:")
    new_height = simpledialog.askinteger("输入高度", "请输入新的窗口高度:")
    if new_width and new_height:
        self.root.geometry(f"{new_width}x{new_height}")
3.5 创建UI组件

计算器的主要UI组件包括显示结果的文本框和包含数字与操作符按钮的按钮面板。

代码语言:javascript复制
def create_widgets(self):
    # 显示结果和输入的只读文本框
    entry = ttk.Entry(self.root, textvariable=self.entry_var, font=("Helvetica", 16), justify="right", state="readonly")
    entry.grid(row=0, column=0, columnspan=5, sticky="nsew", ipadx=8, ipady=8, padx=10, pady=10)

    # 定义按钮
    buttons = [
        '7', '8', '9', '/', 'C',
        '4', '5', '6', '*', '删除',
        '1', '2', '3', '-', '±',
        '0', '.', '=', ' ', 'CE',
        '√', '平方', '1/x'
    ]

    # 创建按钮并添加到窗口中
    for i, button in enumerate(buttons):
        if button != ' ':
            b = ttk.Button(self.root, text=button, bootstyle=SUCCESS if button == '=' else PRIMARY, command=lambda b=button: self.button_press(b))
            b.grid(row=i//5   1, column=i%5, sticky="nsew", padx=5, pady=5)

    # 设置网格权重
    for i in range(5):
        self.root.columnconfigure(i, weight=1)
    for i in range(6):
        self.root.rowconfigure(i   1, weight=1)
3.6 按钮点击事件处理

处理各类按钮点击事件,包括数字、操作符及特殊功能按钮。

代码语言:javascript复制
def button_press(self, button_text):
    current_text = self.entry_var.get()

    if button_text == "C":
        self.entry_var.set("")
    elif button_text == "CE":
        self.entry_var.set("")
        self.history = []
    elif button_text == "删除":
        self.entry_var.set(current_text[:-1])
    elif button_text == "=":
        try:
            result = str(eval(current_text))
            self.history.append(f"{current_text} = {result}")
            self.entry_var.set(result)
        except Exception:
            self.entry_var.set("Error")
    elif button_text == "±":
        if current_text.startswith("-"):
            self.entry_var.set(current_text[1:])
        else:
            self.entry_var.set("-"   current_text)
    elif button_text == "1/x":
        try:
            result = str(1 / float(current_text))
            self.entry_var.set(result)
        except Exception:
            self.entry_var.set("Error")
    elif button_text == "平方":
        try:
            result = str(float(current_text) ** 2)
            self.entry_var.set(result)
        except Exception:
            self.entry_var.set("Error")
    elif button_text == "√":
        try:
            result = str(float(current_text) ** 0.5)
            self.entry_var.set(result)
        except Exception:
            self.entry_var.set("Error")
    else:
        self.entry_var.set(current_text   button_text)
3.7 历史记录、日期和开发者信息

实现查看历史记录、当前日期时间及开发者信息的功能。

代码语言:javascript复制
def show_history(self):
    history_window = Toplevel(self.root)
    history_window.title("历史记录")
    history_window.geometry("320x420")
    
    history_text = Text(history_window, wrap="word")
    history_text.pack(expand=1, fill="both")
    
    for record in self.history:
        history_text.insert("end", record   "n")

def show_date(self):
    current_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    messagebox.showinfo("当前日期和时间", current_date)

def show_developer(self):
    messagebox.showinfo("开发者信息", "开发者: Your Name")
3.8 主程序运行

运行主程序,启动计算器

代码语言:javascript复制
if __name__ == "__main__":
    root = ttk.Window(themename="darkly")
    calculator = Calculator(root)
    root.mainloop()
3.9完整代码分享
代码语言:javascript复制
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import StringVar, Text, Menu, Toplevel, messagebox, simpledialog
import datetime

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("计算器")
        self.root.geometry("320x420")
        self.root.resizable(False, False)
        
        self.entry_var = StringVar()
        self.history = []

        self.create_menu()
        self.create_widgets()

    def create_menu(self):
        menubar = Menu(self.root)

        # 历史记录菜单
        history_menu = Menu(menubar, tearoff=0)
        history_menu.add_command(label="查看历史记录", command=self.show_history)
        menubar.add_cascade(label="历史记录", menu=history_menu)

        # 查看菜单
        view_menu = Menu(menubar, tearoff=0)
        view_menu.add_command(label="查看日期", command=self.show_date)
        view_menu.add_command(label="查看开发者", command=self.show_developer)
        menubar.add_cascade(label="查看", menu=view_menu)

        # 修改菜单
        edit_menu = Menu(menubar, tearoff=0)

        # 修改主题子菜单
        theme_menu = Menu(edit_menu, tearoff=0)
        style = ttk.Style()
        theme_names = style.theme_names()  # 以列表的形式返回多个主题名
        for theme_name in theme_names:
            theme_menu.add_command(label=theme_name, command=lambda t=theme_name: self.change_theme(t))
        edit_menu.add_cascade(label="修改主题", menu=theme_menu)

        # 修改窗口大小功能
        edit_menu.add_command(label="修改窗口大小", command=self.change_window_size)
        menubar.add_cascade(label="修改", menu=edit_menu)

        self.root.config(menu=menubar)

    def change_theme(self, theme_name):
        style = ttk.Style()
        style.theme_use(theme_name)

    def change_window_size(self):
        size = simpledialog.askstring("设置窗口大小", "请输入窗口大小(如800x600):")
        if size:
            self.root.geometry(size)

    def create_widgets(self):
        # 显示结果和输入的只读文本框
        entry = ttk.Entry(self.root, textvariable=self.entry_var, font=("Helvetica", 16), justify="right", state="readonly")
        entry.grid(row=0, column=0, columnspan=5, sticky="nsew", ipadx=8, ipady=8, padx=10, pady=10)

        # 定义按钮
        buttons = [
            '7', '8', '9', '/', 'C',
            '4', '5', '6', '*', '删除',
            '1', '2', '3', '-', '±',
            '0', '.', '=', ' ', 'CE',
            '√', '平方', '1/x'
        ]

        # 创建按钮并添加到窗口中
        for i, button in enumerate(buttons):
            if button != ' ':
                b = ttk.Button(self.root, text=button, bootstyle=SUCCESS if button == '=' else PRIMARY, command=lambda b=button: self.button_press(b))
                b.grid(row=i//5   1, column=i%5, sticky="nsew", padx=5, pady=5)

        # 设置网格权重
        for i in range(5):
            self.root.columnconfigure(i, weight=1)
        for i in range(6):
            self.root.rowconfigure(i   1, weight=1)

    def button_press(self, button_text):
        current_text = self.entry_var.get()

        if button_text == "C":
            self.entry_var.set("")
        elif button_text == "CE":
            self.entry_var.set("")
            self.history = []
        elif button_text == "删除":
            self.entry_var.set(current_text[:-1])
        elif button_text == "=":
            try:
                result = str(eval(current_text))
                self.history.append(f"{current_text} = {result}")
                self.entry_var.set(result)
            except Exception:
                self.entry_var.set("Error")
        elif button_text == "±":
            if current_text.startswith("-"):
                self.entry_var.set(current_text[1:])
            else:
                self.entry_var.set("-"   current_text)
        elif button_text == "1/x":
            try:
                result = str(1 / float(current_text))
                self.entry_var.set(result)
            except Exception:
                self.entry_var.set("Error")
        elif button_text == "平方":
            try:
                result = str(float(current_text) ** 2)
                self.entry_var.set(result)
            except Exception:
                self.entry_var.set("Error")
        elif button_text == "√":
            try:
                result = str(float(current_text) ** 0.5)
                self.entry_var.set(result)
            except Exception:
                self.entry_var.set("Error")
        else:
            self.entry_var.set(current_text   button_text)

    def show_history(self):
        history_window = Toplevel(self.root)
        history_window.title("历史记录")
        history_window.geometry("320x420")
        
        history_text = Text(history_window, wrap="word")
        history_text.pack(expand=1, fill="both")
        
        for record in self.history:
            history_text.insert("end", record   "n")

    def show_date(self):
        current_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        messagebox.showinfo("当前日期和时间", current_date)

    def show_developer(self):
        messagebox.showinfo("开发者信息", "开发者: B站 优秀稳妥的小光")

if __name__ == "__main__":
    root = ttk.Window(themename="darkly")
    calculator = Calculator(root)
    root.mainloop()
4. 功能演示
  • 基本算术运算:支持加、减、乘、除运算,取反、倒数、平方和开方功能。
  • 历史记录:点击“历史记录”菜单中的“查看历史记录”,查看计算历史。
  • 查看日期和开发者信息:点击“查看”菜单中的相应选项,显示当前日期时间和开发者信息。
  • 修改窗口大小和主题:点击“修改”菜单,选择“修改窗口大小”或“修改主题”进行相关设置。
5. 总结

本项目展示了如何使用ttkbootstrap模块创建一个功能齐全且美观的计算器应用程序。通过菜单栏提供的各种功能,用户可以方便地进行主题切换、窗口大小调整、查看历史记录和其他信息等操作。这不仅提高了计算器的实用性,也增强了用户体验。

0 人点赞