【工具】Python开发 之 科学计算器开发

大毛科学计算器 (Scientific Calculator)
作者:
大毛技术网
版本: 1.0.0
日期: 2024-12-17
描述: 一个具有基础计算和科学计算功能的计算器
版权所有 © 2024 大毛技术网. 保留所有权利。

效果

代码

import tkinter as tk
from tkinter import messagebox
import math


class JiSuanQi:
    def __init__(self):
        self.chuangkou = tk.Tk()
        self.chuangkou.title('大毛科学计算器')
        self.chuangkou.geometry('320x480')
        self.chuangkou.configure(bg='#f0f0f0')
        self.chuangkou.resizable(False, False)
        
        # 设置窗口圆角和阴影效果
        try:
            from ctypes import windll, byref, sizeof, c_int
            windll.dwmapi.DwmSetWindowAttribute(
                windll.user32.GetParent(self.chuangkou.winfo_id()),
                20,
                byref(c_int(1)),
                sizeof(c_int)
            )
        except:
            pass
        
        # 添加模式标记
        self.shi_gaoji = False
        # 添加当前表达式变量
        self.dangqian = ''
        
        # 创建切换按钮
        self.qiehuan_anniu = tk.Button(
            self.chuangkou,
            text='科学模式',
            font=('Arial', 10),
            bg='#4a90e2',
            fg='white',
            relief='flat',
            bd=0,
            command=self.qiehuan_moshi
        )
        
        # 设置底部作者
        self.zuozhe_biaoqian = tk.Label(
            self.chuangkou,
            text='By 大毛技术网 © 2024',
            font=('Arial', 10, 'bold'),
            fg='#4a90e2',
            bg='#f0f0f0'
        )
        self.zuozhe_biaoqian.grid(row=7, column=0, columnspan=4, pady=(2, 5))
        
        # 创建界面
        self.chuangjian_xianshi()
        self.chuangjian_jiben_anniu()
        
        # 放置切换按钮
        self.qiehuan_anniu.grid(row=6, column=0, columnspan=4, 
                               padx=4, pady=4, sticky='nsew')

    def chuangjian_xianshi(self):
        # 修改显示框样式
        self.jieguo_var = tk.StringVar()
        self.jieguo_var.set('0')
        self.xianshi = tk.Entry(
            self.chuangkou,
            textvariable=self.jieguo_var,
            justify='right',
            font=('Arial', 32, 'bold'),
            bd=0,
            bg='#ffffff',
            fg='#2c3e50',
            relief='flat',
            state='readonly'
        )
        
        self.xianshi.grid(row=0, column=0, columnspan=4,
                         padx=15, pady=25,
                         sticky='nsew',
                         ipady=20)

    def chuangjian_jiben_anniu(self):
        # 基本按钮文本
        self.basic_texts = [
            'C', '←', '%', '÷',
            '7', '8', '9', 'x',
            '4', '5', '6', '-',
            '1', '2', '3', '+',
            '±', '0', '.', '='
        ]
        self.create_buttons(self.basic_texts)

    def chuangjian_gaoji_anniu(self):
        # 科学计算的按钮文本
        self.advanced_texts = [
            'C', '←', '(', ')',
            'sin', 'cos', 'tan', '÷',
            'π', 'e', 'x²', 'x',
            '√', 'log', 'ln', '-',
            '7', '8', '9', '+',
            '4', '5', '6', '-',
            '1', '2', '3', '=',
            '±', '0', '.', '^'
        ]
        self.create_buttons(self.advanced_texts, advanced=True)

    def create_buttons(self, texts, advanced=False):
        # 清除现有按钮和框架
        for widget in self.chuangkou.grid_slaves():
            if isinstance(widget, (tk.Button, tk.Frame)) and widget != self.xianshi:
                widget.grid_forget()

        # 布局逻辑
        rows = 8 if advanced else 5
        buttons_per_row = 4
        
        # 重置所有行和列的权重
        for i in range(12):  # 使用足够大的数字覆盖所有可能的行
            self.chuangkou.grid_rowconfigure(i, weight=0)
        for i in range(4):
            self.chuangkou.grid_columnconfigure(i, weight=1)
        
        # 设置显示器所在行的权重
        self.chuangkou.grid_rowconfigure(0, weight=1)
        
        for i, text in enumerate(texts):
            row = (i // buttons_per_row) + 1
            col = i % buttons_per_row
            
            # 更新按钮颜色方案
            if text in ['÷', 'x', '-', '+', '=', '^']:
                bg_color = '#ff9500'  # 橙子色运算符
                hover_color = '#ffaa33'  # 悬停时的颜色
                fg_color = 'white'
            elif text in ['C', '←', '%', '±', 'sin', 'cos', 'tan', 'π', 'e', '√', 'log', 'ln', '(', ')', 'x²']:
                bg_color = '#a5a5a5'  # 灰色功能键
                hover_color = '#b8b8b8'  # 悬停时的颜色
                fg_color = 'white'  # 改为白色文字
            else:
                bg_color = '#e8e8e8'  # 更亮的数字键背景
                hover_color = '#f0f0f0'  # 悬停时的颜色
                fg_color = '#2c3e50'  # 深色文字

            # 创建外层框架用于实现缩放效果
            outer_frame = tk.Frame(self.chuangkou, bg='#f0f0f0')
            outer_frame.grid(row=row, column=col, padx=4, pady=4, sticky='nsew')
            outer_frame.grid_columnconfigure(0, weight=1)
            outer_frame.grid_rowconfigure(0, weight=1)

            # 创建内框架用于放置按钮
            inner_frame = tk.Frame(outer_frame, bg=bg_color)
            inner_frame.grid(row=0, column=0, sticky='nsew')
            
            # 配置内框架的网格权重,使按钮居中
            inner_frame.grid_columnconfigure(0, weight=1)
            inner_frame.grid_rowconfigure(0, weight=1)

            button = tk.Button(inner_frame,
                             text=text,
                             font=('Arial', 14, 'bold'),
                             bg=bg_color,
                             fg=fg_color,
                             relief='flat',
                             bd=0,
                             activebackground=hover_color,
                             activeforeground=fg_color,
                             cursor='hand2',
                             anchor='center',  # 设置文本居中
                             width=1,          # 最小宽度,让按钮自适应大小
                             padx=10,
                             pady=8,
                             command=lambda t=text: self.button_click(t))

            # 使用grid布局使按钮填充并居中
            button.grid(row=0, column=0, sticky='nsew')
            
            # 修改悬停和点击效果
            def on_enter(e, btn=button, frame=inner_frame, h_color=hover_color):
                btn.configure(bg=h_color)
                frame.configure(bg=h_color)
                # 使用place_configure来实现平滑的缩放效果
                frame.place(relx=0.02, rely=0.02, relwidth=0.96, relheight=0.96)

            def on_leave(e, btn=button, frame=inner_frame, b_color=bg_color):
                btn.configure(bg=b_color)
                frame.configure(bg=b_color)
                frame.place_forget()
                frame.grid(row=0, column=0, sticky='nsew')

            def on_press(e, btn=button, frame=inner_frame, h_color=hover_color):
                btn.configure(bg=h_color)
                frame.configure(bg=h_color)
                frame.place(relx=0.04, rely=0.04, relwidth=0.92, relheight=0.92)

            def on_release(e, btn=button, frame=inner_frame, b_color=bg_color):
                btn.configure(bg=b_color)
                frame.configure(bg=b_color)
                frame.place_forget()
                frame.grid(row=0, column=0, sticky='nsew')

            button.bind('<Enter>', on_enter)
            button.bind('<Leave>', on_leave)
            button.bind('<Button-1>', on_press)
            button.bind('<ButtonRelease-1>', on_release)

        # 调整切换按钮位置
        if advanced:
            self.qiehuan_anniu.grid(row=9, column=0, columnspan=4, 
                                  padx=4, pady=4, sticky='nsew')
            self.zuozhe_biaoqian.grid(row=10, column=0, columnspan=4, pady=(0, 5))
        else:
            self.qiehuan_anniu.grid(row=6, column=0, columnspan=4, 
                                  padx=4, pady=4, sticky='nsew')
            self.zuozhe_biaoqian.grid(row=7, column=0, columnspan=4, pady=(0, 5))

        # 按钮太丑必须进行美化一下
        self.qiehuan_anniu.configure(
            bg='#4a90e2',
            fg='white',
            font=('Arial', 12, 'bold'),
            relief='flat',
            bd=0,
            padx=15,
            pady=10,
            activebackground='#5c9ee6',
            activeforeground='white'
        )

    def qiehuan_moshi(self):
        self.shi_gaoji = not self.shi_gaoji
        if self.shi_gaoji:
            self.chuangkou.geometry('320x640')
            # 清除所有按钮和框架
            for widget in self.chuangkou.grid_slaves():
                if isinstance(widget, (tk.Button, tk.Frame)) and widget != self.xianshi:
                    widget.grid_forget()
            self.chuangjian_gaoji_anniu()
            self.qiehuan_anniu.configure(text='基础模式')
        else:
            self.chuangkou.geometry('320x480')
            # 清除所有按钮和框架
            for widget in self.chuangkou.grid_slaves():
                if isinstance(widget, (tk.Button, tk.Frame)) and widget != self.xianshi:
                    widget.grid_forget()
            self.chuangjian_jiben_anniu()
            self.qiehuan_anniu.configure(text='科学模式')

    def button_click(self, text):
        # 定义运算符列表
        operators = ['÷', 'x', '-', '+', '^', '%']
        
        # 检查是否是运算符
        if text in operators:
            # 如果当前表达式为空,且不是减号(因为考虑负数的情况),则不添加运算符
            if not self.dangqian and text != '-':
                return
            # 如果最后一个字符是运算符,则不允许再添加运算符
            if self.dangqian and self.dangqian[-1] in operators:
                return
            
        if text == 'x':
            self.dangqian += 'x'
        elif text == '÷':
            self.dangqian += '÷'
        elif text == 'C':
            self.dangqian = ''
            self.jieguo_var.set('0')
        elif text == '←':
            self.dangqian = self.dangqian[:-1]
            self.jieguo_var.set(self.dangqian if self.dangqian else '0')
        elif text == '=':
            # 如果最后一个字符是运算符,则不进行计算
            if self.dangqian and self.dangqian[-1] in operators:
                messagebox.showerror('错误', '别闹,没这样的运算')
                return
            try:
                # 科学计算器的特殊函数
                expr = self.dangqian
                expr = expr.replace('x', '*').replace('÷', '/')
                expr = expr.replace('π', str(math.pi))
                expr = expr.replace('e', str(math.e))
                expr = expr.replace('sin', 'math.sin')
                expr = expr.replace('cos', 'math.cos')
                expr = expr.replace('tan', 'math.tan')
                expr = expr.replace('log', 'math.log10')
                expr = expr.replace('ln', 'math.log')
                expr = expr.replace('√', 'math.sqrt')
                expr = expr.replace('^', '**')
                
                # 处理阶乘
                if '!' in expr:
                    num = float(expr.replace('!', ''))
                    if num.is_integer() and num >= 0:
                        result = math.factorial(int(num))
                    else:
                        raise ValueError("别闹,没这样的运算")
                else:
                    result = eval(expr)
                
                # 格式化结果
                if isinstance(result, float):
                    result = '{:.3f}'.format(result).rstrip('0').rstrip('.')
                self.jieguo_var.set(result)
                self.dangqian = str(result)
            except Exception as e:
                messagebox.showerror('错误', '别闹,没这样的运算')
                self.dangqian = ''
                self.jieguo_var.set('0')
        elif text == 'x²':
            try:
                if self.dangqian:
                    num = eval(self.dangqian)
                    result = num * num
                    if isinstance(result, float):
                        result = '{:.3f}'.format(result).rstrip('0').rstrip('.')
                    self.dangqian = str(result)
                    self.jieguo_var.set(result)
            except:
                messagebox.showerror('错误', '别闹,没这样的运算')
        elif text == '±':
            try:
                if self.dangqian:
                    if self.dangqian[0] == '-':
                        self.dangqian = self.dangqian[1:]
                    else:
                        self.dangqian = '-' + self.dangqian
                    self.jieguo_var.set(self.dangqian)
            except:
                pass
        else:
            self.dangqian += text
        self.jieguo_var.set(self.dangqian)

    def run(self):
        self.chuangkou.mainloop()


if __name__ == '__main__':
    calc = JiSuanQi()
    calc.run()

代码打包

首先执行以下命令安装Python打包所需要的pip工具(如果提示你的pip版本过低,请先执行升级命令)

pip install pyinstaller

随后切换到你当前项目下后右键打开终端,随后执行以下命令进行打包([jisuanqi.py]根据实际修改成你自己的)

pyinstaller --onefile --windowed jisuanqi.py

© 版权声明
THE END
喜欢就支持一下吧
点赞16赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容