某一个“天” 发表于 2025-7-5 10:51:46

娱乐版计算器来了,有音效、彩蛋(66育碧

本帖最后由 某一个“天” 于 2025-7-5 13:03 编辑

{:10_256:}

前几天肚子不舒服,但现在完成了这个功能最全花里胡哨的计算器,
但体积太大发不上论坛,稍后简朴版的计算器我试试减小点体积


本期简介
彩蛋有按钮悬浮在等于号上时,其他按钮显示出 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")
      if s:
            treeview.insert("", ttk.END, values=)
    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 =
            varLabel0.set("计算过程区:")
            varEntry0.set(txt)
      else:
            varLabel0.set("计算过程区:")
            input_list = list(varEntry0.get())# 结果部分
            varEntry0.set(varEntry0.get())
      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)] + "√"
      input_list.pop()
      varEntry0.set(varEntry0.get()[:-1])
    # 以下需特殊处理,另起if使其不被重复记录
    if txt == "±":
      is_old_entry_part(txt, False)
      if varEntry0.get() == "-":
            varEntry0.set(varEntry0.get())
            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()
                if i == 0 and x == "0" and varEntry0.get() != ".":
                  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] == "(":# 找成对的括号
                _ += 1
                if _ == n:
                  only_fact = False
                  m = len(input_list) - i - 1
                  break
            elif input_list[::-1] in ("+", "-", "*", "/", "%", "//", "^"):
                only_fact = False
                m = len(input_list) - i
                if _ >= n:
                  break
      if only_fact:
            input_list.insert(0, "!")
      else:
            input_list = ["!"]# 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 =
      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 == "-" 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 in "⁰¹²³⁴⁵⁶⁷⁸⁹":
            _x_rt = "⁰¹²³⁴⁵⁶⁷⁸⁹".find(item)
            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 = 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(".")) > 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()

    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 =
      # 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 = [, , ,       , ,
         ,               ,
         , ,         ,
         ,               ,
         ,                     , ]
'''
    单击事件绑定
      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 =
      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
欢迎评分{:13_430:}


某一个“天” 发表于 2025-7-5 10:52:36

本帖最后由 某一个“天” 于 2025-7-5 20:10 编辑

记得替换成自己的主题,音效{:10_281:}
Ttkbootstrap和Pygame要下载,如在cmd 输入
pip install xxx

某一个“天” 发表于 2025-7-5 10:53:52

本帖最后由 某一个“天” 于 2025-7-5 10:55 编辑

@不二如是 @sfqxx @isdkz @zhangjinxuan @python爱好者. @小甲鱼的三师弟 @fishc.com @~风介~

某一个“天” 发表于 2025-7-5 10:54:08

@fishc.com @~风介~ @小甲鱼的二师兄 @player-none @py木木

某一个“天” 发表于 2025-7-5 10:56:18

@的名额不够了{:10_266:}{:10_266:}

小甲鱼 发表于 2025-7-5 12:10:07

居然还有音效?这你受得了!!

小甲鱼 发表于 2025-7-5 12:10:42

小甲鱼 发表于 2025-7-5 12:10
居然还有音效?这你受得了!!

我去,咋中了这么大奖 {:13_447:}

某一个“天” 发表于 2025-7-5 12:59:44

小甲鱼 发表于 2025-7-5 12:10
居然还有音效?这你受得了!!

厉害,暗调概率{:10_334:}
(甲鱼哥运气真好

奋斗中的鱼 发表于 2025-7-5 13:48:44

哇,大工程啊,厉害!

Crayonl 发表于 2025-7-5 13:52:38

这音效...

某一个“天” 发表于 2025-7-5 15:01:21

奋斗中的鱼 发表于 2025-7-5 13:48
哇,大工程啊,厉害!

评个分呗{:10_254:}

sfqxx 发表于 2025-7-5 15:33:13

哇塞又更新了

不二如是 发表于 2025-7-5 16:17:50

期待!!!继续迭代升级

pyzyd 发表于 2025-7-5 16:32:51

厉害!

Mr.江南 发表于 2025-7-5 17:39:39

{:5_106:}

sfqxx_小 发表于 2025-7-5 18:59:54

支持

某一个“天” 发表于 2025-7-5 19:07:12

sfqxx_小 发表于 2025-7-5 18:59
支持

小号评个分呗{:10_275:}

cjjJasonchen 发表于 2025-7-5 20:01:04

这个音频文件是pygame或者win自带的吗

tk 和 pygame 都是外包库,要标注一下哦{:10_275:}

某一个“天” 发表于 2025-7-5 20:08:41

cjjJasonchen 发表于 2025-7-5 20:01
这个音频文件是pygame或者win自带的吗

tk 和 pygame 都是外包库,要标注一下哦

OK,我标一下

sunshine_8205 发表于 2025-7-5 21:52:09

{:5_106:}{:5_106:}{:5_106:}
页: [1] 2
查看完整版本: 娱乐版计算器来了,有音效、彩蛋(66育碧