|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 某一个“天” 于 2025-7-5 13:03 编辑
前几天肚子不舒服,但现在完成了这个功能最全花里胡哨的计算器,
但体积太大发不上论坛,稍后简朴版的计算器我试试减小点体积
本期简介
彩蛋有按钮悬浮在等于号上时,其他按钮显示出 FC 字样。
还有美丽的分割线
编辑方面增加了功能,使键盘和鼠标都能轻松使用,输入框支持 CV 大法,改进显示逻辑
详细介绍
全FishC最好的计算器!
消除误差!0.1+0.2 可以等于 0.3!
过大或过小的数值会用科学计数法
任选角度测量制度(默认角度制)
输入框支持一切windows支持的操作
历史记录无限存储,支持滚轮(每个新算式都有美丽的分界线)
有右键菜单复制,删除。可多选
出现“错误”后,使用CE后输入正确数值即可继续计算
注意:
恢复默认只会对[基本的设置有效
阶乘 ! 是括号之下优先级最高的运算
根运算后不加括号将只算数字
小数点后取 7 位(可调整),采用银行家舍入
【四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一】
支持鼠标点击和键盘输入(非常神奇),但不能混合使用
其中键盘输入: 退格-->删除(CE),回车-->计算(=),Delete-->清屏(AC)
键入0b, 0o, 0x前缀(大小写均可)后回车可以转换为十进制。
计算的十进制结果可直接转换为 2, 8, 16 进制
甚至还可以动态调整运算精度
全部代码
- """frame框架布局
- 在frame内部,可以重新进行一次布局"""
- # 1.增加2nd 2.只写改变的值
- import ttkbootstrap as ttk
- from tkinter.messagebox import showinfo
- from PIL import ImageTk, Image
- from decimal import Decimal
- from math import sqrt, sin, cos, tan, pi, radians, factorial
- from pygame import mixer
- __auther__ = "__sky__"
- use_big = True
- is_x08 = False
- digits_after_point = 7
- sounds_volume = 0.3
- point_method = "智能取"
- angle_method = "角度制"
- side_method = "left"
- entry_text_colour = "Gold"
- separate_str = "✩‧₊☾•¨•.¸¸♪✧♫•¨•.¸¸♪·★₊˚☾.·˖✶✩\n"
- FC_symbol = False
- mixer.init()
- # 加载音频文件
- normal_sound = mixer.Sound("rain.mp3")
- calcu_sound = mixer.Sound("calcu.mp3")
- def style_init():
- main_style.configure("TButton", font=("Comic Sans MS", 14))
- main_style.configure("My.info.Treeview", font=("Comic Sans MS", 12), rowheight=20)
- main_style.configure("My.info.Treeview.Heading", font=("Arial", 13))
- main_style.configure("My.primary.TButton", font=10)
- def set_box_buttons(is_disable):
- # 遍历box中的所有子组件,即按钮
- if is_disable:
- for child in box.winfo_children():
- menu_bar.entryconfig("整数进制转换", state=ttk.DISABLED)
- child.config(state=ttk.DISABLED)
- child.unbind("<ButtonRelease-1>")
- else:
- for child in box.winfo_children():
- child.config(state=ttk.NORMAL)
- child.bind("<ButtonRelease-1>", calcu) # 左键抬起事件
- def resize_window():
- global use_big
- # set_box_buttons(True)
- step = 0
- def worker(u_big):
- nonlocal step
- if u_big:
- win.geometry(f"{432 - step}x344")
- step += 24
- btn_equal.grid_forget()
- if step <= 144:
- win.after(10, worker, u_big)
- else:
- win.geometry(f"{288 + step}x344")
- step += 24
- btn_equal.grid_forget()
- if step <= 144:
- win.after(10, worker, u_big)
- worker(use_big)
- # set_box_buttons(False)
- use_big = not use_big
- def restore_defaults():
- global digits_after_point, point_method, angle_method, side_method
- digits_after_point = 7
- point_method = "智能取"
- angle_method = "角度制"
- side_method = "left"
- def top1():
- top = ttk.Toplevel(title="详情")
- label = ttk.Label(master=top, text="""
- 全FishC最好的计算器!
- 消除误差!0.1+0.2 可以等于 0.3!
- 过大或过小的数值会用科学计数法
- 任选角度测量制度(默认角度制)
- 输入框支持一切windows支持的操作
- 历史记录无限存储,支持滚轮(每个新算式都有美丽的分界线)
- 有右键菜单复制,删除。可多选
- 出现“错误”后,使用CE后输入正确数值即可继续计算
- 注意:
- 恢复默认只会对[基本]的设置有效
- 阶乘 ! 是括号之下优先级最高的运算
- 根运算后不加括号将只算数字
- 小数点后取 7 位(可调整),采用银行家舍入
- 【四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一】
- 支持鼠标点击和键盘输入(非常神奇),但不能混合使用
- 其中键盘输入: 退格-->删除(CE),回车-->计算(=),Delete-->清屏(AC)
- 键入0b, 0o, 0x前缀(大小写均可)后回车可以转换为十进制。
- 计算的十进制结果可直接转换为 2, 8, 16 进制
- 甚至还可以动态调整运算精度
- """,
- font=("思源黑体", 13))
- label.pack()
- def top2():
- top = ttk.Toplevel(title="作者")
- label = ttk.Label(master=top,
- text="""作者:FishC 某一个“天”
- ~谢谢使用~""",
- font=("Arial", 12))
- label.pack()
- def top3():
- def show_right_click_menu(event):
- if len(treeview.selection()) <= 1: # 考虑多选
- # 获取点击位置的项 ID
- item_id = treeview.identify("item", event.x, event.y)
- if item_id:
- treeview.selection_set(item_id) # 选中该项
- # 显示右键菜单
- right_click_menu.post(event.x_root, event.y_root)
- def copy_selected_item():
- # 获取当前选中的项
- selected_item = treeview.selection()
- top.clipboard_clear() # 清空剪贴板
- for item in selected_item:
- # 获取选中的项的列值
- item_text = "".join(treeview.item(item)['values'])
- # 将数据转换为字符串,并复制到剪贴板
- top.clipboard_append(item_text + "\n") # 将数据追加到剪贴板
- top.update() # 更新剪贴板内容
- def delete_selected_item():
- # 获取当前选中的项
- selected_item = treeview.selection()
- for item in selected_item:
- # 删除选中的项
- treeview.delete(item)
- top = ttk.Toplevel(title="历史记录")
- top.geometry("288x288")
- top.minsize(288, 288)
- top.resizable(width=True, height=False) # 设置不能调整窗口纵向大小
- # 创建 Treeview
- treeview = ttk.Treeview(top, columns=["Column 1"], show="headings", style="My.info.Treeview", height=12)
- # 定义列标题
- treeview.heading("Column 1", text="右键菜单,可多选 倒序 ")
- # 创建右键菜单
- right_click_menu = ttk.Menu(treeview, tearoff=0)
- right_click_menu.config(bg="Lightblue", activebackground="LightPink")
- right_click_menu.add_command(label="复制", command=copy_selected_item)
- right_click_menu.add_command(label="删除", command=delete_selected_item)
- # 绑定右键点击事件
- treeview.bind("<Button-3>", show_right_click_menu)
- history_input = "".join(history_input_list)
- for i in range(history_input.count("\n")):
- s = history_input.split("\n")[i]
- if s:
- treeview.insert("", ttk.END, values=[s])
- treeview.pack(fill="x")
- def reverse_order():
- children = treeview.get_children()
- for child in reversed(children):
- treeview.move(child, '', ttk.END) # 将每一项移动到最后面
- reverse_button = ttk.Button(treeview, text="↺", command=reverse_order, style="My.primary.TButton")
- reverse_button.place(relx=0.85, y=2, relheight=0.114, relwidth=0.15)
- def top4():
- def write_change():
- history_separate()
- history_input_list.append(f"记录!角度测量制度是<{var_rbtn2.get()}>\n")
- history_input_list.append(f"记录!小数点后取<{digits_after_point}>位\n")
- history_input_list.append(f"记录!取舍方法是<{point_method}>\n")
- history_separate()
- def show_scale_change(val):
- var_digits_value.set(f"0-·-·-·小数点后取{str(int(float(val))).center(2, ' ')}位·-·-·-20")
- def change_digits_value():
- global digits_after_point
- digits_after_point = int(float(sc1.get()))
- def change_point_method():
- global point_method
- point_method = var_rbtn1.get()
- def change_angle_method():
- global angle_method
- angle_method = var_rbtn2.get()
- def change_side_method():
- global side_method
- side_method = var_rbtn3.get()
- if side_method == "left":
- main_label.config(anchor="w")
- elif side_method == "right":
- main_label.config(anchor="e")
- main_entry.config(justify=side_method)
- top = ttk.Toplevel(title="设置")
- top.geometry("320x310")
- top.resizable(width=False, height=False) # 设置不能调整窗口大小
- global digits_after_point, angle_method, point_method, sounds_volume
- # 创建 Notebook 控件
- notebook = ttk.Notebook(top)
- basic_frame = ttk.Frame(notebook)
- var_digits_value = ttk.StringVar()
- var_digits_value.set(f"0-·-·-·小数点后取{str(digits_after_point).center(2, ' ')}位·-·-·-20")
- l1 = ttk.Label(basic_frame, textvariable=var_digits_value, style="success", font=9)
- l1.pack()
- sc1 = ttk.Scale(basic_frame, length=275, from_=0, to=20, value=digits_after_point, command=show_scale_change)
- sc1.pack()
- var_rbtn1 = ttk.StringVar()
- var_rbtn1.set(point_method) # 开始时选中智能取
- rbtn1 = ttk.Radiobutton(basic_frame, text="智能取", value="智能取", variable=var_rbtn1, style="success")
- rbtn1.place(x=60, y=40)
- rbtn2 = ttk.Radiobutton(basic_frame, text="强制取", value="强制取", variable=var_rbtn1, style="success")
- rbtn2.place(x=190, y=40)
- l2 = ttk.Label(basic_frame, text="角度测量制度", style="primary", font=9)
- l2.place(x=105, y=65)
- var_rbtn2 = ttk.StringVar()
- var_rbtn2.set(angle_method) # 开始时选中角度制
- rbtn3 = ttk.Radiobutton(basic_frame, text="角度制", value="角度制", variable=var_rbtn2, style="primary")
- rbtn3.place(x=60, y=90)
- rbtn4 = ttk.Radiobutton(basic_frame, text="弧度制", value="弧度制", variable=var_rbtn2, style="primary")
- rbtn4.place(x=190, y=90)
- l3 = ttk.Label(basic_frame, text="文本对齐方式", style="info", font=9)
- l3.place(x=105, y=115)
- var_rbtn3 = ttk.StringVar()
- var_rbtn3.set(side_method) # 开始时选中左对齐
- rbtn5 = ttk.Radiobutton(basic_frame, text="左对齐", value="left", variable=var_rbtn3, style="info")
- rbtn5.place(x=60, y=140)
- rbtn6 = ttk.Radiobutton(basic_frame, text="右对齐", value="right", variable=var_rbtn3, style="info")
- rbtn6.place(x=190, y=140)
- tip_l = ttk.Label(basic_frame, text="*设置需应用才生效\n勾选记录可在历史记录中找到", foreground="red")
- tip_l.place(x=90, y=170)
- var_cbtn = ttk.BooleanVar()
- # 创建一个对勾单选框
- checkbox = ttk.Checkbutton(basic_frame, text="记录", variable=var_cbtn)
- checkbox.place(x=200, y=245)
- def apply1():
- change_digits_value()
- change_point_method()
- change_angle_method()
- change_side_method()
- if var_cbtn.get(): # 勾选记录
- write_change()
- apply_btn1 = ttk.Button(basic_frame, text="应用", command=apply1, style="success")
- apply_btn1.place(x=100, y=230)
- themes_frame = ttk.Frame(notebook)
- l1 = ttk.Label(themes_frame, text="FishC彩蛋:")
- l1.grid(column=0, row=0, padx=5, pady=30)
- # 创建下拉菜单
- options1 = ["关闭", "正常", "增强"]
- combobox1 = ttk.Combobox(themes_frame, values=options1)
- combobox1.grid(column=1, row=0, padx=5, pady=30)
- l2 = ttk.Label(themes_frame, text="主题样式:")
- l2.grid(column=0, row=1, padx=5)
- options2 = ["晴日", "阴雨", "夜幕"]
- combobox2 = ttk.Combobox(themes_frame, values=options2)
- combobox2.grid(column=1, row=1, padx=5)
- # 调节音量
- l2 = ttk.Label(themes_frame, text="音量0~1:")
- l2.grid(column=0, row=2, padx=5, pady=30)
- sc2 = ttk.Scale(themes_frame, length=170, from_=0.0, to=1.0, value=sounds_volume)
- sc2.grid(column=1, row=2, padx=5, pady=30)
- def apply2():
- global main_style, entry_text_colour, normal_sound, sounds_volume, FC_symbol, separate_str
- if combobox1.get() == "关闭":
- FC_symbol = False
- separate_str = "✩‧₊☾•¨•.¸¸♪✧♫•¨•.¸¸♪·★₊˚☾.·˖✶✩\n"
- elif combobox1.get() == "正常":
- FC_symbol = False
- separate_str = "FC•¨FishC♪✧♫•₊¨FishC♪·₊˚☾.·FC✩\n"
- elif combobox1.get() == "增强":
- FC_symbol = True
- separate_str = "FC•¨FishC♪✧♫•₊¨FishC♪·₊˚☾.·FC✩\n"
- if combobox2.get() == "晴日":
- normal_sound = mixer.Sound("normal.mp3")
- entry_text_colour = "SeaGreen"
- main_style.theme_use("my_light")
- elif combobox2.get() == "阴雨":
- normal_sound = mixer.Sound("rain.mp3")
- entry_text_colour = "Gold"
- main_style.theme_use("my_gray")
- elif combobox2.get() == "夜幕":
- normal_sound = mixer.Sound("normal.mp3")
- entry_text_colour = "HotPink"
- main_style.theme_use("my_dark")
- style_init()
- sounds_volume = float(sc2.get())
- apply_btn2 = ttk.Button(themes_frame, text="应用", command=apply2, style="success")
- apply_btn2.grid(column=0, row=3, columnspan=2, padx=5, pady=20)
- # 向 Notebook 添加选项卡
- notebook.add(basic_frame, text="基本")
- notebook.add(themes_frame, text="高级")
- notebook.pack(fill="both")
- # 写在后面防覆盖
- close_btn = ttk.Button(top, text="关闭", command=top.destroy, style="My.primary.TButton")
- close_btn.place(x=260, y=270)
- win = ttk.Window()
- win.title("FishC最好的?计算器")
- win.geometry("432x367+500+200")
- win.resizable(width=False, height=False) # 设置不能调整窗口大小
- # 设置窗体图标
- win.iconbitmap("./calculater_icon.ico")
- # 创建菜单栏
- menu_bar = ttk.Menu(win)
- win.config(menu=menu_bar)
- # 创建菜单项
- info_menu = ttk.Menu(menu_bar, tearoff=False)
- info_menu.add_command(label="详情", command=top1)
- info_menu.add_command(label="作者", command=top2)
- menu_bar.add_cascade(label="关于", menu=info_menu)
- history_menu = ttk.Menu(menu_bar, tearoff=False)
- history_menu.add_command(label="查看", command=top3)
- history_menu.add_command(label="清空", command=lambda: history_input_list.clear())
- menu_bar.add_cascade(label="历史记录", menu=history_menu)
- system_menu = ttk.Menu(menu_bar, tearoff=False)
- system_menu.add_command(label="转为二进制",
- command=lambda: showinfo("二进制", f"得数转为二进制是{int(eval(get_result(input_list))):b}"))
- system_menu.add_command(label="转为八进制",
- command=lambda: showinfo("八进制", f"得数转为八进制是{int(eval(get_result(input_list))):o}"))
- system_menu.add_command(label="转为十六进制", command=lambda: showinfo("十六进制",
- f"得数转为十六进制是"
- f"{int(eval(get_result(input_list))):x}"))
- menu_bar.add_cascade(label="整数进制转换", menu=system_menu)
- control_menu = ttk.Menu(menu_bar, tearoff=False)
- control_menu.add_command(label="调整", command=top4)
- control_menu.add_command(label="恢复默认", command=restore_defaults)
- control_menu.add_command(label="使用精简版/科学版", command=resize_window)
- menu_bar.add_cascade(label="设置", menu=control_menu)
- menu_bar.entryconfig("整数进制转换", state=ttk.DISABLED)
- main_style = ttk.Style("my_gray") # 我自己配的主题,可以用以下替代
- # ['cosmo', 'flatly', 'litera', 'minty', 'lumen', 'sandstone', 'yeti', 'pulse',
- # 'united', 'morph', 'journal', 'darkly', 'superhero', 'solar', 'cyborg', 'vapor', 'simplex', 'cerculean']
- style_init()
- input_list = []
- history_input_list = []
- wait_new_key_start = True
- def x_rt(x, num):
- return num ** (1 / Decimal(x))
- def my_factorial(num):
- try:
- return factorial(int(num))
- except Exception as e:
- print(e)
- varEntry0.set("错误")
- def my_sqrt(num):
- return Decimal(sqrt(num))
- def my_sin(num):
- if angle_method == "角度制":
- angle_in_radians = radians(num)
- return Decimal(sin(angle_in_radians))
- else:
- return Decimal(sin(num))
- def my_cos(num):
- if angle_method == "角度制":
- angle_in_radians = radians(num)
- return Decimal(cos(angle_in_radians))
- else:
- return Decimal(cos(num))
- def my_tan(num):
- if angle_method == "角度制":
- angle_in_radians = radians(num)
- return Decimal(tan(angle_in_radians))
- else:
- return Decimal(tan(num))
- def history_separate():
- if history_input_list and "✩" not in history_input_list[-1]:
- history_input_list.append(separate_str)
- def _clear(is_key_delete=False):
- history_separate()
- input_list.clear()
- varLabel0.set("计算过程区:")
- varEntry0.set("")
- main_entry.focus_set()
- main_entry.config(state=ttk.NORMAL)
- if is_key_delete:
- solve_key(event="key_delete") # delete
- return "break"
- def fast_add(master, text):
- master.set(master.get() + text)
- def solve_key(event=None, disable=False):
- global input_list, wait_new_key_start, is_x08
- normal_sound.set_volume(sounds_volume) # 设置音量
- normal_sound.play()
- if event == "key_delete": # 二次处理
- for child in box.winfo_children():
- child.config(state=ttk.NORMAL)
- child.bind("<ButtonRelease-1>", calcu) # 左键抬起事件
- return None # 提前跳出,不会禁用box按键
- char: str = event.char # 要放在二次处理的后面,否则报错
- if char.isalpha() and char.lower() not in ("a", "b", "c", "d", "e",
- "e", "f", "x", "o"): # 有用的字符
- return "break"
- if char in ["+", "-", "*", "/", "%", "^"]:
- key_continue(char)
- elif event.keysym == "Delete": # 防止和C冲突
- btn_equal.config(state=ttk.NORMAL)
- _clear(True)
- return "break" # 让c无法出现
- elif char == "\r":
- if "错误" not in varEntry0.get():
- equal_click(is_key=True)
- set_box_buttons(False)
- return None
- elif ("错误" in varEntry0.get() or "\u200b" in varEntry0.get()) and char == "\x08": # 按下了删除,且有
- varEntry0.set("\u200b")
- return "break" # 让刚set的\u200b不会被删
- if disable and char.isdigit() and ("=" in varEntry0.get() or "错误" in varEntry0.get()): # 新的算式
- _clear()
- if disable:
- btn_equal.config(state=ttk.DISABLED)
- else:
- btn_equal.config(state=ttk.NORMAL)
- set_box_buttons(disable)
- def is_old_entry_part(txt, is_usual=True):
- global input_list
- if "=" in varEntry0.get() or "错误" in varEntry0.get(): # 新的算式
- if is_usual:
- history_separate()
- input_list = [txt]
- varLabel0.set("计算过程区:")
- varEntry0.set(txt)
- else:
- varLabel0.set("计算过程区:")
- input_list = list(varEntry0.get()[1:]) # 结果部分
- varEntry0.set(varEntry0.get()[1:])
- return False
- return True
- def calcu(event):
- global input_list, wait_new_key_start
- if varLabel0.get() == "计算过程区:":
- varLabel0.set("")
- try:
- txt = str(event.widget["text"])
- normal_sound.set_volume(sounds_volume) # 设置音量
- normal_sound.play()
- menu_bar.entryconfig("整数进制转换", state=ttk.NORMAL)
- main_entry.config(state=ttk.DISABLED, foreground=entry_text_colour) # 禁用同时颜色不变
- except AttributeError:
- if wait_new_key_start:
- _clear()
- wait_new_key_start = False
- txt = event
- if txt == "取余":
- txt = "%"
- elif txt == "整除":
- txt = "//"
- elif txt == "xʸ":
- txt = "^"
- elif "x" in txt and txt != "x":
- txt = txt.replace("x", "").replace(" ", "")
- elif txt == "ˣ√y":
- s = "⁰¹²³⁴⁵⁶⁷⁸⁹"
- txt = s[int(input_list[-1])] + "√"
- input_list.pop()
- varEntry0.set(varEntry0.get()[:-1])
- # 以下需特殊处理,另起if使其不被重复记录
- if txt == "±":
- is_old_entry_part(txt, False)
- if varEntry0.get()[0] == "-":
- varEntry0.set(varEntry0.get()[1:])
- input_list.reverse()
- input_list.remove("-")
- input_list.reverse()
- elif varEntry0.get() == "0":
- pass
- else:
- _ = 0
- for i in range(len(varEntry0.get())):
- x = varEntry0.get()[i]
- if i == 0 and x == "0" and varEntry0.get()[i + 1] != ".":
- break
- elif x == "." or type(eval(x)) == int:
- _ -= 1
- else:
- input_list.insert(_, "-")
- varEntry0.set("-" + varEntry0.get())
- elif txt == "!":
- only_fact = True
- _ = 0
- n = input_list.count(")")
- m = 0
- for i in range(len(input_list)):
- if input_list[::-1][i] == "(": # 找成对的括号
- _ += 1
- if _ == n:
- only_fact = False
- m = len(input_list) - i - 1
- break
- elif input_list[::-1][i] in ("+", "-", "*", "/", "%", "//", "^"):
- only_fact = False
- m = len(input_list) - i
- if _ >= n:
- break
- if only_fact:
- input_list.insert(0, "!")
- else:
- input_list[m:m] = ["!"] # input_list.insert(m, "!")
- elif txt != "." or varEntry0.get()[-1] != ".":
- input_list.append(txt)
- if txt == "AC": # 清空
- _clear()
- elif txt == "CE":
- if "=" not in varEntry0.get(): # 不能删除得数
- input_list.pop() # 把CE删掉
- if varEntry0.get() == "错误":
- varEntry0.set("")
- input_list = [i for i in varLabel0.get()]
- elif varEntry0.get(): # 保证输入框有东西
- input_list.pop() # 真正要删除的
- if "=" not in varEntry0.get():
- varEntry0.set(varEntry0.get()[:-1])
- elif "=" not in varEntry0.get():
- if varLabel0.get()[-2:] == "//":
- varLabel0.set(varLabel0.get()[:-2])
- else:
- varLabel0.set(varLabel0.get()[:-1])
- # 省略乘号
- elif (txt in ("π", "√", "(")) or set(txt) & set("⁰¹²³⁴⁵⁶⁷⁸⁹"):
- try:
- if is_old_entry_part(txt=txt):
- fast_add(varEntry0, txt)
- # 有 IndexError: list index out of range 的危险
- if input_list[-2] in ("π", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
- input_list.insert(-1, "*")
- except Exception as e:
- print(e)
- elif txt in ("+", "-", "*", "/", "%", "//", "^", "!"):
- if "=" in varEntry0.get(): # 上一个结果进行新运算
- varEntry0.set("")
- varLabel0.set("".join(input_list))
- elif any(map(lambda x: x in varLabel0.get(),
- ["+", "-", "*", "/", "%", "//", "^", "!"])):
- varLabel0.set(varLabel0.get() + varEntry0.get() + txt)
- varEntry0.set("")
- else:
- if "(" in varEntry0.get() and ")" not in varEntry0.get(): # 分行
- fast_add(varEntry0, txt) # 正常输入
- else:
- if txt == "-" and input_list[0] == "-" and input_list.count("-") == 1: # 负号而不是减号
- if is_old_entry_part(txt=txt):
- fast_add(varEntry0, txt) # 正常输入
- else:
- varLabel0.set(varEntry0.get() + txt)
- varEntry0.set("")
- else:
- if is_old_entry_part(txt=txt) and txt != "±":
- if txt != "." or varEntry0.get()[-1] != ".": # Bug!防止多个.
- fast_add(varEntry0, txt) # 正常输入数字的情况
- def split_list(lst, *delimiter):
- result = []
- current_part = []
- have_right_bracket = 0
- for item in lst:
- # Another: if set(item) & set("⁰¹²³⁴⁵⁶⁷⁸⁹"):
- if item[0] in "⁰¹²³⁴⁵⁶⁷⁸⁹":
- _x_rt = "⁰¹²³⁴⁵⁶⁷⁸⁹".find(item[0])
- current_part.append(f"x_rt({_x_rt},")
- have_right_bracket += 1
- elif item == "√":
- current_part.append("my_sqrt(")
- have_right_bracket += 1
- elif item == "π":
- current_part.append(str(pi))
- elif item in ("sin", "cos", "tan"):
- item = "my_" + item + "("
- have_right_bracket += 1
- elif item == "!":
- item = "my_factorial("
- have_right_bracket += 1
- if item in delimiter:
- if item == "^":
- item = "**"
- if current_part: # 确保当前部分不为空
- result.append(current_part)
- current_part = []
- if have_right_bracket and item != "(":
- result.append(")")
- have_right_bracket -= 1
- result.append(item)
- elif item[-1] not in ("√", ")", "π", "!"): # 加上[-1]防止x_rt
- current_part.append(item) # 数字,三角函数
- while have_right_bracket:
- current_part.append(")")
- have_right_bracket -= 1
- if current_part: # 添加最后一部分(如果存在)
- result.append(current_part)
- return result
- def get_result(lst):
- splited_result = split_list(lst, "(", ")", "+", "-", "*", "/", "%", "//", "^")
- splited_result = ["".join(i) for i in splited_result]
- index = 0
- result = 0
- for each in splited_result:
- try:
- splited_result[index] = repr(Decimal(each))
- except Exception as e:
- print(e)
- index += 1
- try:
- result = eval("".join(splited_result))
- except Exception as e: # 可能由各种原因导致
- varEntry0.set("错误")
- if point_method == "强制取":
- result = f"{result:.{digits_after_point}f}"
- else:
- try:
- result = str(result)
- if len(result.split(".")[1]) > digits_after_point:
- result = str(Decimal(result).quantize(Decimal(f"0.{'0' * digits_after_point}")))
- except Exception as e:
- print(e)
- if len(result) > 18:
- result = f"{Decimal(result):.{digits_after_point}e}".replace("e+0", "").replace("E+0", "") # 去掉可能没意义的e+0
- elif "E" in result: # 很短的位数却使用科学计数法:Decimal('2') / Decimal('0.1')
- result = str(float(result))
- if "错误" not in varEntry0.get():
- history_input_list.extend([varLabel0.get() + varEntry0.get(), "=", result, "\n"])
- return result
- def equal_click(is_key=False):
- global input_list, wait_new_key_start
- # if "=" not in varEntry0.get():
- calcu_sound.set_volume(sounds_volume) # 设置音量
- calcu_sound.play()
- menu_bar.entryconfig("整数进制转换", state=ttk.NORMAL)
- if is_key:
- btn_equal.config(state=ttk.NORMAL)
- if "\u200b" in varEntry0.get(): # 零宽空格=>键盘删除了错误
- varEntry0.set(varEntry0.get().replace("\u200B", ""))
- tmp_varLabel0 = varLabel0.get()
- tmp_varEntry0 = varEntry0.get()
- wait_new_key_start = False
- _clear()
- for s in tmp_varLabel0 + tmp_varEntry0:
- calcu(s)
- varLabel0.set(tmp_varLabel0)
- varEntry0.set(tmp_varEntry0)
- else:
- wait_new_key_start = True
- for i in varEntry0.get():
- calcu(i)
- else:
- main_entry.config(state=ttk.NORMAL)
- main_entry.focus_set()
- result = str(get_result(input_list))
- if varEntry0.get() != "错误":
- input_list = [result]
- # if varEntry0.get() != varEntry0.get():
- varLabel0.set(varLabel0.get() + varEntry0.get())
- varEntry0.set("=" + result)
- main_entry.icursor(ttk.END) # 光标移到最后
- def key_continue(i):
- is_old_entry_part(txt=i, is_usual=False)
- # 显示结果部分
- varLabel0 = ttk.StringVar()
- varLabel0.set("计算过程区:")
- main_label = ttk.Label(win, font=("Open Sans", 15), textvariable=varLabel0)
- main_label.pack(fill="x")
- varEntry0 = ttk.StringVar()
- main_entry = ttk.Entry(win, font=("微软雅黑", 16), textvariable=varEntry0)
- # main_entry.grid_columnconfigure(0, weight=1) # 设置第一列权重为1
- main_entry.pack(fill="x")
- # main_entry.bind("<Control-v>", lambda event: input_list.extend(main_entry.clipboard_get())) # 绑定键盘事件
- # main_entry.bind("<Control-x>", lambda event: input_list.extend(main_entry.get())) # 绑定键盘事件
- main_entry.bind("<Key>", lambda event: solve_key(event, disable=True)) # 禁用所有按钮
- # main_entry.bind("<Return>", lambda event: equal_click(is_key=True)) # 绑定键盘事件
- # main_entry.bind("<c>", lambda event: _clear())
- main_entry.focus_set() # 开始时鼠标焦点在输入框,以便键入
- # 按钮部分
- # 创建frame框架
- box = ttk.Frame(win)
- box.pack(fill="x")
- # 按钮文本的列表
- btn_text_list = [["(", ")", "√x", "/", "ˣ√y", "sin x"],
- ["7", "8", "9", "*", "xʸ", "cos x"],
- ["4", "5", "6", "-", "取余", "tan x"],
- ["1", "2", "3", "+", "整除", "x!"],
- ["±", "0", ".", "CE", "AC", "π"]]
- FC_list = [[0, 0], [0, 1], [0, 2], [0, 4], [0, 5],
- [1, 0], [1, 3],
- [2, 0], [2, 1], [2, 3],
- [3, 0], [3, 3],
- [4, 0], [4, 4], [4, 5]]
- '''
- 单击事件绑定
- 1.command只能绑定一个,如果要传参可以用lambda表达式
- 2.bind可以传当前控件事件到自定义函数
- '''
- # 行和列
- ri = 0
- ci = 0
- # 通过循环批量制作按钮
- for i in btn_text_list:
- for each in i:
- each = ttk.Button(box, text=each, width=4, style="warning-outline")
- each.bind("<ButtonRelease-1>", calcu) # 左键抬起事件
- each.name = [ri, ci]
- each.grid(row=ri, column=ci)
- ci += 1
- ri += 1
- ci = 0
- def on_hover(event):
- if FC_symbol:
- for child in box.winfo_children():
- if child.name in FC_list:
- child.config(style="danger.TButton")
- def on_leave(event):
- if FC_symbol:
- for child in box.winfo_children():
- if child.name in FC_list:
- child.config(bootstyle="warning-outline")
- # =按钮
- pic_equal = Image.open("./equal_image.png") # 载入图片对象
- pic_equal = pic_equal.resize((225, 60)) # 一个元组
- pic_equal = ImageTk.PhotoImage(pic_equal) # 变成适合ttk的图片格式
- btn_equal = ttk.Button(win, image=pic_equal, command=equal_click, style="danger", name="btn_equal")
- # 绑定鼠标悬停和离开事件
- btn_equal.bind("<Enter>", on_hover) # 鼠标进入按钮
- btn_equal.bind("<Leave>", on_leave) # 鼠标离开按钮
- btn_equal.pack(fill="x")
- if __auther__ == "__sky__": # 这句没有任何作用,冒充__name__ == "__main__"
- win.mainloop()
复制代码
Last but not least
欢迎评分
|
评分
-
参与人数 5 | 荣誉 +21 |
鱼币 +23 |
贡献 +19 |
C币 +12 |
收起
理由
|
pyzyd
| + 3 |
+ 5 |
+ 1 |
|
鱼C有你更精彩^_^ |
不二如是
| + 6 |
+ 6 |
+ 6 |
+ 6 |
鱼C有你更精彩^_^ |
sfqxx
| + 1 |
+ 1 |
+ 3 |
|
|
ba21
| + 5 |
+ 5 |
+ 3 |
|
鱼C有你更精彩^_^ |
小甲鱼
| + 6 |
+ 6 |
+ 6 |
+ 6 |
感谢楼主无私奉献! |
查看全部评分
|