鱼C论坛

 找回密码
 立即注册
查看: 82|回复: 16

[技术交流] 娱乐版计算器来了,有音效、彩蛋(66育碧

[复制链接]
回帖奖励 33 鱼币 回复本帖可获得 11 鱼币奖励! 每人限 1 次(中奖概率 60%)
发表于 8 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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 进制
甚至还可以动态调整运算精度


全部代码
  1. """frame框架布局
  2.     在frame内部,可以重新进行一次布局"""
  3. # 1.增加2nd 2.只写改变的值
  4. import ttkbootstrap as ttk
  5. from tkinter.messagebox import showinfo
  6. from PIL import ImageTk, Image
  7. from decimal import Decimal
  8. from math import sqrt, sin, cos, tan, pi, radians, factorial
  9. from pygame import mixer

  10. __auther__ = "__sky__"
  11. use_big = True
  12. is_x08 = False
  13. digits_after_point = 7
  14. sounds_volume = 0.3
  15. point_method = "智能取"
  16. angle_method = "角度制"
  17. side_method = "left"
  18. entry_text_colour = "Gold"
  19. separate_str = "✩‧₊☾•¨•.¸¸♪✧♫•¨•.¸¸♪·★₊˚☾.·˖✶✩\n"
  20. FC_symbol = False

  21. mixer.init()
  22. # 加载音频文件
  23. normal_sound = mixer.Sound("rain.mp3")
  24. calcu_sound = mixer.Sound("calcu.mp3")


  25. def style_init():
  26.     main_style.configure("TButton", font=("Comic Sans MS", 14))
  27.     main_style.configure("My.info.Treeview", font=("Comic Sans MS", 12), rowheight=20)
  28.     main_style.configure("My.info.Treeview.Heading", font=("Arial", 13))
  29.     main_style.configure("My.primary.TButton", font=10)


  30. def set_box_buttons(is_disable):
  31.     # 遍历box中的所有子组件,即按钮
  32.     if is_disable:
  33.         for child in box.winfo_children():
  34.             menu_bar.entryconfig("整数进制转换", state=ttk.DISABLED)
  35.             child.config(state=ttk.DISABLED)
  36.             child.unbind("<ButtonRelease-1>")
  37.     else:
  38.         for child in box.winfo_children():
  39.             child.config(state=ttk.NORMAL)
  40.             child.bind("<ButtonRelease-1>", calcu)  # 左键抬起事件


  41. def resize_window():
  42.     global use_big
  43.     # set_box_buttons(True)
  44.     step = 0

  45.     def worker(u_big):
  46.         nonlocal step
  47.         if u_big:
  48.             win.geometry(f"{432 - step}x344")
  49.             step += 24
  50.             btn_equal.grid_forget()
  51.             if step <= 144:
  52.                 win.after(10, worker, u_big)
  53.         else:
  54.             win.geometry(f"{288 + step}x344")
  55.             step += 24
  56.             btn_equal.grid_forget()
  57.             if step <= 144:
  58.                 win.after(10, worker, u_big)

  59.     worker(use_big)
  60.     # set_box_buttons(False)
  61.     use_big = not use_big


  62. def restore_defaults():
  63.     global digits_after_point, point_method, angle_method, side_method
  64.     digits_after_point = 7
  65.     point_method = "智能取"
  66.     angle_method = "角度制"
  67.     side_method = "left"


  68. def top1():
  69.     top = ttk.Toplevel(title="详情")
  70.     label = ttk.Label(master=top, text="""
  71.     全FishC最好的计算器!

  72.     消除误差!0.1+0.2 可以等于 0.3!
  73.     过大或过小的数值会用科学计数法
  74.     任选角度测量制度(默认角度制)
  75.     输入框支持一切windows支持的操作
  76.     历史记录无限存储,支持滚轮(每个新算式都有美丽的分界线)
  77.     有右键菜单复制,删除。可多选
  78.     出现“错误”后,使用CE后输入正确数值即可继续计算
  79.     注意:
  80.     恢复默认只会对[基本]的设置有效
  81.     阶乘 ! 是括号之下优先级最高的运算
  82.     根运算后不加括号将只算数字
  83.     小数点后取 7 位(可调整),采用银行家舍入
  84.     【四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一】
  85.     支持鼠标点击和键盘输入(非常神奇),但不能混合使用
  86.     其中键盘输入: 退格-->删除(CE),回车-->计算(=),Delete-->清屏(AC)
  87.     键入0b, 0o, 0x前缀(大小写均可)后回车可以转换为十进制。
  88.     计算的十进制结果可直接转换为 2, 8, 16 进制
  89.     甚至还可以动态调整运算精度
  90.                                        """,
  91.                       font=("思源黑体", 13))
  92.     label.pack()


  93. def top2():
  94.     top = ttk.Toplevel(title="作者")
  95.     label = ttk.Label(master=top,
  96.                       text="""作者:FishC 某一个“天”
  97.                                   ~谢谢使用~""",
  98.                       font=("Arial", 12))
  99.     label.pack()


  100. def top3():
  101.     def show_right_click_menu(event):
  102.         if len(treeview.selection()) <= 1:  # 考虑多选
  103.             # 获取点击位置的项 ID
  104.             item_id = treeview.identify("item", event.x, event.y)
  105.             if item_id:
  106.                 treeview.selection_set(item_id)  # 选中该项
  107.         # 显示右键菜单
  108.         right_click_menu.post(event.x_root, event.y_root)

  109.     def copy_selected_item():
  110.         # 获取当前选中的项
  111.         selected_item = treeview.selection()
  112.         top.clipboard_clear()  # 清空剪贴板
  113.         for item in selected_item:
  114.             # 获取选中的项的列值
  115.             item_text = "".join(treeview.item(item)['values'])
  116.             # 将数据转换为字符串,并复制到剪贴板
  117.             top.clipboard_append(item_text + "\n")  # 将数据追加到剪贴板
  118.             top.update()  # 更新剪贴板内容

  119.     def delete_selected_item():
  120.         # 获取当前选中的项
  121.         selected_item = treeview.selection()
  122.         for item in selected_item:
  123.             # 删除选中的项
  124.             treeview.delete(item)

  125.     top = ttk.Toplevel(title="历史记录")
  126.     top.geometry("288x288")
  127.     top.minsize(288, 288)
  128.     top.resizable(width=True, height=False)  # 设置不能调整窗口纵向大小
  129.     # 创建 Treeview
  130.     treeview = ttk.Treeview(top, columns=["Column 1"], show="headings", style="My.info.Treeview", height=12)
  131.     # 定义列标题
  132.     treeview.heading("Column 1", text="右键菜单,可多选            倒序    ")

  133.     # 创建右键菜单
  134.     right_click_menu = ttk.Menu(treeview, tearoff=0)
  135.     right_click_menu.config(bg="Lightblue", activebackground="LightPink")
  136.     right_click_menu.add_command(label="复制", command=copy_selected_item)
  137.     right_click_menu.add_command(label="删除", command=delete_selected_item)
  138.     # 绑定右键点击事件
  139.     treeview.bind("<Button-3>", show_right_click_menu)

  140.     history_input = "".join(history_input_list)
  141.     for i in range(history_input.count("\n")):
  142.         s = history_input.split("\n")[i]
  143.         if s:
  144.             treeview.insert("", ttk.END, values=[s])
  145.     treeview.pack(fill="x")

  146.     def reverse_order():
  147.         children = treeview.get_children()
  148.         for child in reversed(children):
  149.             treeview.move(child, '', ttk.END)  # 将每一项移动到最后面
  150.     reverse_button = ttk.Button(treeview, text="&#8634;", command=reverse_order, style="My.primary.TButton")
  151.     reverse_button.place(relx=0.85, y=2, relheight=0.114, relwidth=0.15)


  152. def top4():
  153.     def write_change():
  154.         history_separate()
  155.         history_input_list.append(f"记录!角度测量制度是<{var_rbtn2.get()}>\n")
  156.         history_input_list.append(f"记录!小数点后取<{digits_after_point}>位\n")
  157.         history_input_list.append(f"记录!取舍方法是<{point_method}>\n")
  158.         history_separate()

  159.     def show_scale_change(val):
  160.         var_digits_value.set(f"0-·-·-·小数点后取{str(int(float(val))).center(2, ' ')}位·-·-·-20")

  161.     def change_digits_value():
  162.         global digits_after_point
  163.         digits_after_point = int(float(sc1.get()))

  164.     def change_point_method():
  165.         global point_method
  166.         point_method = var_rbtn1.get()

  167.     def change_angle_method():
  168.         global angle_method
  169.         angle_method = var_rbtn2.get()

  170.     def change_side_method():
  171.         global side_method
  172.         side_method = var_rbtn3.get()
  173.         if side_method == "left":
  174.             main_label.config(anchor="w")
  175.         elif side_method == "right":
  176.             main_label.config(anchor="e")
  177.         main_entry.config(justify=side_method)

  178.     top = ttk.Toplevel(title="设置")
  179.     top.geometry("320x310")
  180.     top.resizable(width=False, height=False)  # 设置不能调整窗口大小

  181.     global digits_after_point, angle_method, point_method, sounds_volume

  182.     # 创建 Notebook 控件
  183.     notebook = ttk.Notebook(top)
  184.     basic_frame = ttk.Frame(notebook)

  185.     var_digits_value = ttk.StringVar()
  186.     var_digits_value.set(f"0-·-·-·小数点后取{str(digits_after_point).center(2, ' ')}位·-·-·-20")
  187.     l1 = ttk.Label(basic_frame, textvariable=var_digits_value, style="success", font=9)
  188.     l1.pack()
  189.     sc1 = ttk.Scale(basic_frame, length=275, from_=0, to=20, value=digits_after_point, command=show_scale_change)
  190.     sc1.pack()
  191.     var_rbtn1 = ttk.StringVar()
  192.     var_rbtn1.set(point_method)  # 开始时选中智能取
  193.     rbtn1 = ttk.Radiobutton(basic_frame, text="智能取", value="智能取", variable=var_rbtn1, style="success")
  194.     rbtn1.place(x=60, y=40)
  195.     rbtn2 = ttk.Radiobutton(basic_frame, text="强制取", value="强制取", variable=var_rbtn1, style="success")
  196.     rbtn2.place(x=190, y=40)
  197.     l2 = ttk.Label(basic_frame, text="角度测量制度", style="primary", font=9)
  198.     l2.place(x=105, y=65)
  199.     var_rbtn2 = ttk.StringVar()
  200.     var_rbtn2.set(angle_method)  # 开始时选中角度制
  201.     rbtn3 = ttk.Radiobutton(basic_frame, text="角度制", value="角度制", variable=var_rbtn2, style="primary")
  202.     rbtn3.place(x=60, y=90)
  203.     rbtn4 = ttk.Radiobutton(basic_frame, text="弧度制", value="弧度制", variable=var_rbtn2, style="primary")
  204.     rbtn4.place(x=190, y=90)
  205.     l3 = ttk.Label(basic_frame, text="文本对齐方式", style="info", font=9)
  206.     l3.place(x=105, y=115)
  207.     var_rbtn3 = ttk.StringVar()
  208.     var_rbtn3.set(side_method)  # 开始时选中左对齐
  209.     rbtn5 = ttk.Radiobutton(basic_frame, text="左对齐", value="left", variable=var_rbtn3, style="info")
  210.     rbtn5.place(x=60, y=140)
  211.     rbtn6 = ttk.Radiobutton(basic_frame, text="右对齐", value="right", variable=var_rbtn3, style="info")
  212.     rbtn6.place(x=190, y=140)
  213.     tip_l = ttk.Label(basic_frame, text="*设置需应用才生效\n勾选记录可在历史记录中找到", foreground="red")
  214.     tip_l.place(x=90, y=170)
  215.     var_cbtn = ttk.BooleanVar()
  216.     # 创建一个对勾单选框
  217.     checkbox = ttk.Checkbutton(basic_frame, text="记录", variable=var_cbtn)
  218.     checkbox.place(x=200, y=245)

  219.     def apply1():
  220.         change_digits_value()
  221.         change_point_method()
  222.         change_angle_method()
  223.         change_side_method()
  224.         if var_cbtn.get():  # 勾选记录
  225.             write_change()
  226.     apply_btn1 = ttk.Button(basic_frame, text="应用", command=apply1, style="success")
  227.     apply_btn1.place(x=100, y=230)

  228.     themes_frame = ttk.Frame(notebook)
  229.     l1 = ttk.Label(themes_frame, text="FishC彩蛋:")
  230.     l1.grid(column=0, row=0, padx=5, pady=30)
  231.     # 创建下拉菜单
  232.     options1 = ["关闭", "正常", "增强"]
  233.     combobox1 = ttk.Combobox(themes_frame, values=options1)
  234.     combobox1.grid(column=1, row=0, padx=5, pady=30)
  235.     l2 = ttk.Label(themes_frame, text="主题样式:")
  236.     l2.grid(column=0, row=1, padx=5)
  237.     options2 = ["晴日", "阴雨", "夜幕"]
  238.     combobox2 = ttk.Combobox(themes_frame, values=options2)
  239.     combobox2.grid(column=1, row=1, padx=5)
  240.     # 调节音量
  241.     l2 = ttk.Label(themes_frame, text="音量0~1:")
  242.     l2.grid(column=0, row=2, padx=5, pady=30)
  243.     sc2 = ttk.Scale(themes_frame, length=170, from_=0.0, to=1.0, value=sounds_volume)
  244.     sc2.grid(column=1, row=2, padx=5, pady=30)

  245.     def apply2():
  246.         global main_style, entry_text_colour, normal_sound, sounds_volume, FC_symbol, separate_str
  247.         if combobox1.get() == "关闭":
  248.             FC_symbol = False
  249.             separate_str = "&#10025;&#8231;&#8330;&#9790;&#8226;¨&#8226;.&#184;&#184;&#9834;&#10023;&#9835;&#8226;¨&#8226;.&#184;&#184;&#9834;·★&#8330;&#730;&#9790;.·&#726;&#10038;&#10025;\n"
  250.         elif combobox1.get() == "正常":
  251.             FC_symbol = False
  252.             separate_str = "FC&#8226;¨FishC&#9834;&#10023;&#9835;&#8226;&#8330;¨FishC&#9834;·&#8330;&#730;&#9790;.·FC&#10025;\n"
  253.         elif combobox1.get() == "增强":
  254.             FC_symbol = True
  255.             separate_str = "FC&#8226;¨FishC&#9834;&#10023;&#9835;&#8226;&#8330;¨FishC&#9834;·&#8330;&#730;&#9790;.·FC&#10025;\n"
  256.         if combobox2.get() == "晴日":
  257.             normal_sound = mixer.Sound("normal.mp3")
  258.             entry_text_colour = "SeaGreen"
  259.             main_style.theme_use("my_light")
  260.         elif combobox2.get() == "阴雨":
  261.             normal_sound = mixer.Sound("rain.mp3")
  262.             entry_text_colour = "Gold"
  263.             main_style.theme_use("my_gray")
  264.         elif combobox2.get() == "夜幕":
  265.             normal_sound = mixer.Sound("normal.mp3")
  266.             entry_text_colour = "HotPink"
  267.             main_style.theme_use("my_dark")
  268.         style_init()
  269.         sounds_volume = float(sc2.get())
  270.     apply_btn2 = ttk.Button(themes_frame, text="应用", command=apply2, style="success")
  271.     apply_btn2.grid(column=0, row=3, columnspan=2, padx=5, pady=20)

  272.     # 向 Notebook 添加选项卡
  273.     notebook.add(basic_frame, text="基本")
  274.     notebook.add(themes_frame, text="高级")

  275.     notebook.pack(fill="both")
  276.     # 写在后面防覆盖
  277.     close_btn = ttk.Button(top, text="关闭", command=top.destroy, style="My.primary.TButton")
  278.     close_btn.place(x=260, y=270)


  279. win = ttk.Window()
  280. win.title("FishC最好的?计算器")
  281. win.geometry("432x367+500+200")
  282. win.resizable(width=False, height=False)  # 设置不能调整窗口大小
  283. # 设置窗体图标
  284. win.iconbitmap("./calculater_icon.ico")
  285. # 创建菜单栏
  286. menu_bar = ttk.Menu(win)
  287. win.config(menu=menu_bar)
  288. # 创建菜单项
  289. info_menu = ttk.Menu(menu_bar, tearoff=False)
  290. info_menu.add_command(label="详情", command=top1)
  291. info_menu.add_command(label="作者", command=top2)
  292. menu_bar.add_cascade(label="关于", menu=info_menu)

  293. history_menu = ttk.Menu(menu_bar, tearoff=False)
  294. history_menu.add_command(label="查看", command=top3)
  295. history_menu.add_command(label="清空", command=lambda: history_input_list.clear())
  296. menu_bar.add_cascade(label="历史记录", menu=history_menu)

  297. system_menu = ttk.Menu(menu_bar, tearoff=False)
  298. system_menu.add_command(label="转为二进制",
  299.                         command=lambda: showinfo("二进制", f"得数转为二进制是{int(eval(get_result(input_list))):b}"))
  300. system_menu.add_command(label="转为八进制",
  301.                         command=lambda: showinfo("八进制", f"得数转为八进制是{int(eval(get_result(input_list))):o}"))
  302. system_menu.add_command(label="转为十六进制", command=lambda: showinfo("十六进制",
  303.                                                                        f"得数转为十六进制是"
  304.                                                                        f"{int(eval(get_result(input_list))):x}"))
  305. menu_bar.add_cascade(label="整数进制转换", menu=system_menu)

  306. control_menu = ttk.Menu(menu_bar, tearoff=False)
  307. control_menu.add_command(label="调整", command=top4)
  308. control_menu.add_command(label="恢复默认", command=restore_defaults)
  309. control_menu.add_command(label="使用精简版/科学版", command=resize_window)
  310. menu_bar.add_cascade(label="设置", menu=control_menu)

  311. menu_bar.entryconfig("整数进制转换", state=ttk.DISABLED)

  312. main_style = ttk.Style("my_gray")  # 我自己配的主题,可以用以下替代
  313. # ['cosmo', 'flatly', 'litera', 'minty', 'lumen', 'sandstone', 'yeti', 'pulse',
  314. # 'united', 'morph', 'journal', 'darkly', 'superhero', 'solar', 'cyborg', 'vapor', 'simplex', 'cerculean']
  315. style_init()

  316. input_list = []
  317. history_input_list = []
  318. wait_new_key_start = True


  319. def x_rt(x, num):
  320.     return num ** (1 / Decimal(x))


  321. def my_factorial(num):
  322.     try:
  323.         return factorial(int(num))
  324.     except Exception as e:
  325.         print(e)
  326.         varEntry0.set("错误")


  327. def my_sqrt(num):
  328.     return Decimal(sqrt(num))


  329. def my_sin(num):
  330.     if angle_method == "角度制":
  331.         angle_in_radians = radians(num)
  332.         return Decimal(sin(angle_in_radians))
  333.     else:
  334.         return Decimal(sin(num))


  335. def my_cos(num):
  336.     if angle_method == "角度制":
  337.         angle_in_radians = radians(num)
  338.         return Decimal(cos(angle_in_radians))
  339.     else:
  340.         return Decimal(cos(num))


  341. def my_tan(num):
  342.     if angle_method == "角度制":
  343.         angle_in_radians = radians(num)
  344.         return Decimal(tan(angle_in_radians))
  345.     else:
  346.         return Decimal(tan(num))


  347. def history_separate():
  348.     if history_input_list and "&#10025;" not in history_input_list[-1]:
  349.         history_input_list.append(separate_str)


  350. def _clear(is_key_delete=False):
  351.     history_separate()
  352.     input_list.clear()
  353.     varLabel0.set("计算过程区:")
  354.     varEntry0.set("")
  355.     main_entry.focus_set()
  356.     main_entry.config(state=ttk.NORMAL)

  357.     if is_key_delete:
  358.         solve_key(event="key_delete")  # delete
  359.     return "break"


  360. def fast_add(master, text):
  361.     master.set(master.get() + text)


  362. def solve_key(event=None, disable=False):
  363.     global input_list, wait_new_key_start, is_x08
  364.     normal_sound.set_volume(sounds_volume)  # 设置音量
  365.     normal_sound.play()
  366.     if event == "key_delete":  # 二次处理
  367.         for child in box.winfo_children():
  368.             child.config(state=ttk.NORMAL)
  369.             child.bind("<ButtonRelease-1>", calcu)  # 左键抬起事件
  370.         return None  # 提前跳出,不会禁用box按键

  371.     char: str = event.char  # 要放在二次处理的后面,否则报错
  372.     if char.isalpha() and char.lower() not in ("a", "b", "c", "d", "e",
  373.                                                "e", "f", "x", "o"):  # 有用的字符
  374.         return "break"

  375.     if char in ["+", "-", "*", "/", "%", "^"]:
  376.         key_continue(char)
  377.     elif event.keysym == "Delete":  # 防止和C冲突
  378.         btn_equal.config(state=ttk.NORMAL)
  379.         _clear(True)
  380.         return "break"  # 让c无法出现
  381.     elif char == "\r":
  382.         if "错误" not in varEntry0.get():
  383.             equal_click(is_key=True)
  384.         set_box_buttons(False)
  385.         return None
  386.     elif ("错误" in varEntry0.get() or "\u200b" in varEntry0.get()) and char == "\x08":  # 按下了删除,且有
  387.         varEntry0.set("\u200b")
  388.         return "break"  # 让刚set的\u200b不会被删
  389.     if disable and char.isdigit() and ("=" in varEntry0.get() or "错误" in varEntry0.get()):  # 新的算式
  390.         _clear()

  391.     if disable:
  392.         btn_equal.config(state=ttk.DISABLED)
  393.     else:
  394.         btn_equal.config(state=ttk.NORMAL)

  395.     set_box_buttons(disable)


  396. def is_old_entry_part(txt, is_usual=True):
  397.     global input_list
  398.     if "=" in varEntry0.get() or "错误" in varEntry0.get():  # 新的算式
  399.         if is_usual:
  400.             history_separate()
  401.             input_list = [txt]
  402.             varLabel0.set("计算过程区:")
  403.             varEntry0.set(txt)
  404.         else:
  405.             varLabel0.set("计算过程区:")
  406.             input_list = list(varEntry0.get()[1:])  # 结果部分
  407.             varEntry0.set(varEntry0.get()[1:])
  408.         return False
  409.     return True


  410. def calcu(event):
  411.     global input_list, wait_new_key_start

  412.     if varLabel0.get() == "计算过程区:":
  413.         varLabel0.set("")
  414.     try:
  415.         txt = str(event.widget["text"])
  416.         normal_sound.set_volume(sounds_volume)  # 设置音量
  417.         normal_sound.play()
  418.         menu_bar.entryconfig("整数进制转换", state=ttk.NORMAL)
  419.         main_entry.config(state=ttk.DISABLED, foreground=entry_text_colour)  # 禁用同时颜色不变

  420.     except AttributeError:
  421.         if wait_new_key_start:
  422.             _clear()
  423.             wait_new_key_start = False
  424.         txt = event

  425.     if txt == "取余":
  426.         txt = "%"
  427.     elif txt == "整除":
  428.         txt = "//"
  429.     elif txt == "x&#696;":
  430.         txt = "^"
  431.     elif "x" in txt and txt != "x":
  432.         txt = txt.replace("x", "").replace(" ", "")
  433.     elif txt == "&#739;√y":
  434.         s = "&#8304;&#185;&#178;&#179;&#8308;&#8309;&#8310;&#8311;&#8312;&#8313;"
  435.         txt = s[int(input_list[-1])] + "√"
  436.         input_list.pop()
  437.         varEntry0.set(varEntry0.get()[:-1])
  438.     # 以下需特殊处理,另起if使其不被重复记录
  439.     if txt == "±":
  440.         is_old_entry_part(txt, False)
  441.         if varEntry0.get()[0] == "-":
  442.             varEntry0.set(varEntry0.get()[1:])
  443.             input_list.reverse()
  444.             input_list.remove("-")
  445.             input_list.reverse()
  446.         elif varEntry0.get() == "0":
  447.             pass
  448.         else:
  449.             _ = 0
  450.             for i in range(len(varEntry0.get())):
  451.                 x = varEntry0.get()[i]
  452.                 if i == 0 and x == "0" and varEntry0.get()[i + 1] != ".":
  453.                     break
  454.                 elif x == "." or type(eval(x)) == int:
  455.                     _ -= 1
  456.             else:
  457.                 input_list.insert(_, "-")
  458.                 varEntry0.set("-" + varEntry0.get())
  459.     elif txt == "!":
  460.         only_fact = True
  461.         _ = 0
  462.         n = input_list.count(")")
  463.         m = 0
  464.         for i in range(len(input_list)):
  465.             if input_list[::-1][i] == "(":  # 找成对的括号
  466.                 _ += 1
  467.                 if _ == n:
  468.                     only_fact = False
  469.                     m = len(input_list) - i - 1
  470.                     break
  471.             elif input_list[::-1][i] in ("+", "-", "*", "/", "%", "//", "^"):
  472.                 only_fact = False
  473.                 m = len(input_list) - i
  474.                 if _ >= n:
  475.                     break
  476.         if only_fact:
  477.             input_list.insert(0, "!")
  478.         else:
  479.             input_list[m:m] = ["!"]  # input_list.insert(m, "!")
  480.     elif txt != "." or varEntry0.get()[-1] != ".":
  481.         input_list.append(txt)

  482.     if txt == "AC":  # 清空
  483.         _clear()

  484.     elif txt == "CE":
  485.         if "=" not in varEntry0.get():  # 不能删除得数
  486.             input_list.pop()  # 把CE删掉
  487.         if varEntry0.get() == "错误":
  488.             varEntry0.set("")
  489.             input_list = [i for i in varLabel0.get()]
  490.         elif varEntry0.get():  # 保证输入框有东西
  491.             input_list.pop()  # 真正要删除的
  492.             if "=" not in varEntry0.get():
  493.                 varEntry0.set(varEntry0.get()[:-1])
  494.             elif "=" not in varEntry0.get():
  495.                 if varLabel0.get()[-2:] == "//":
  496.                     varLabel0.set(varLabel0.get()[:-2])
  497.                 else:
  498.                     varLabel0.set(varLabel0.get()[:-1])
  499.     # 省略乘号
  500.     elif (txt in ("π", "√", "(")) or set(txt) & set("&#8304;&#185;&#178;&#179;&#8308;&#8309;&#8310;&#8311;&#8312;&#8313;"):
  501.         try:
  502.             if is_old_entry_part(txt=txt):
  503.                 fast_add(varEntry0, txt)
  504.                 # 有 IndexError: list index out of range 的危险
  505.                 if input_list[-2] in ("π", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
  506.                     input_list.insert(-1, "*")
  507.         except Exception as e:
  508.             print(e)

  509.     elif txt in ("+", "-", "*", "/", "%", "//", "^", "!"):
  510.         if "=" in varEntry0.get():  # 上一个结果进行新运算
  511.             varEntry0.set("")
  512.             varLabel0.set("".join(input_list))
  513.         elif any(map(lambda x: x in varLabel0.get(),
  514.                      ["+", "-", "*", "/", "%", "//", "^", "!"])):
  515.             varLabel0.set(varLabel0.get() + varEntry0.get() + txt)
  516.             varEntry0.set("")
  517.         else:
  518.             if "(" in varEntry0.get() and ")" not in varEntry0.get():  # 分行
  519.                 fast_add(varEntry0, txt)  # 正常输入
  520.             else:
  521.                 if txt == "-" and input_list[0] == "-" and input_list.count("-") == 1:  # 负号而不是减号
  522.                     if is_old_entry_part(txt=txt):
  523.                         fast_add(varEntry0, txt)  # 正常输入
  524.                 else:
  525.                     varLabel0.set(varEntry0.get() + txt)
  526.                     varEntry0.set("")

  527.     else:
  528.         if is_old_entry_part(txt=txt) and txt != "±":
  529.             if txt != "." or varEntry0.get()[-1] != ".":  # Bug!防止多个.
  530.                 fast_add(varEntry0, txt)  # 正常输入数字的情况


  531. def split_list(lst, *delimiter):
  532.     result = []
  533.     current_part = []
  534.     have_right_bracket = 0
  535.     for item in lst:
  536.         # Another: if set(item) & set("&#8304;&#185;&#178;&#179;&#8308;&#8309;&#8310;&#8311;&#8312;&#8313;"):
  537.         if item[0] in "&#8304;&#185;&#178;&#179;&#8308;&#8309;&#8310;&#8311;&#8312;&#8313;":
  538.             _x_rt = "&#8304;&#185;&#178;&#179;&#8308;&#8309;&#8310;&#8311;&#8312;&#8313;".find(item[0])
  539.             current_part.append(f"x_rt({_x_rt},")
  540.             have_right_bracket += 1
  541.         elif item == "√":
  542.             current_part.append("my_sqrt(")
  543.             have_right_bracket += 1
  544.         elif item == "π":
  545.             current_part.append(str(pi))
  546.         elif item in ("sin", "cos", "tan"):
  547.             item = "my_" + item + "("
  548.             have_right_bracket += 1
  549.         elif item == "!":
  550.             item = "my_factorial("
  551.             have_right_bracket += 1

  552.         if item in delimiter:
  553.             if item == "^":
  554.                 item = "**"
  555.             if current_part:  # 确保当前部分不为空
  556.                 result.append(current_part)
  557.                 current_part = []
  558.                 if have_right_bracket and item != "(":
  559.                     result.append(")")
  560.                     have_right_bracket -= 1
  561.             result.append(item)
  562.         elif item[-1] not in ("√", ")", "π", "!"):  # 加上[-1]防止x_rt
  563.             current_part.append(item)  # 数字,三角函数

  564.     while have_right_bracket:
  565.         current_part.append(")")
  566.         have_right_bracket -= 1
  567.     if current_part:  # 添加最后一部分(如果存在)
  568.         result.append(current_part)
  569.     return result


  570. def get_result(lst):
  571.     splited_result = split_list(lst, "(", ")", "+", "-", "*", "/", "%", "//", "^")
  572.     splited_result = ["".join(i) for i in splited_result]
  573.     index = 0
  574.     result = 0
  575.     for each in splited_result:
  576.         try:
  577.             splited_result[index] = repr(Decimal(each))
  578.         except Exception as e:
  579.             print(e)

  580.         index += 1

  581.     try:
  582.         result = eval("".join(splited_result))
  583.     except Exception as e:  # 可能由各种原因导致
  584.         varEntry0.set("错误")

  585.     if point_method == "强制取":
  586.         result = f"{result:.{digits_after_point}f}"
  587.     else:
  588.         try:
  589.             result = str(result)
  590.             if len(result.split(".")[1]) > digits_after_point:
  591.                 result = str(Decimal(result).quantize(Decimal(f"0.{'0' * digits_after_point}")))
  592.         except Exception as e:
  593.             print(e)

  594.     if len(result) > 18:
  595.         result = f"{Decimal(result):.{digits_after_point}e}".replace("e+0", "").replace("E+0", "")  # 去掉可能没意义的e+0
  596.     elif "E" in result:  # 很短的位数却使用科学计数法:Decimal('2') / Decimal('0.1')
  597.         result = str(float(result))
  598.     if "错误" not in varEntry0.get():
  599.         history_input_list.extend([varLabel0.get() + varEntry0.get(), "=", result, "\n"])

  600.     return result


  601. def equal_click(is_key=False):
  602.     global input_list, wait_new_key_start
  603.     # if "=" not in varEntry0.get():
  604.     calcu_sound.set_volume(sounds_volume)  # 设置音量
  605.     calcu_sound.play()
  606.     menu_bar.entryconfig("整数进制转换", state=ttk.NORMAL)

  607.     if is_key:
  608.         btn_equal.config(state=ttk.NORMAL)
  609.         if "\u200b" in varEntry0.get():  # 零宽空格=>键盘删除了错误
  610.             varEntry0.set(varEntry0.get().replace("\u200B", ""))
  611.             tmp_varLabel0 = varLabel0.get()
  612.             tmp_varEntry0 = varEntry0.get()
  613.             wait_new_key_start = False
  614.             _clear()
  615.             for s in tmp_varLabel0 + tmp_varEntry0:
  616.                 calcu(s)
  617.             varLabel0.set(tmp_varLabel0)
  618.             varEntry0.set(tmp_varEntry0)
  619.         else:
  620.             wait_new_key_start = True
  621.             for i in varEntry0.get():
  622.                 calcu(i)
  623.     else:
  624.         main_entry.config(state=ttk.NORMAL)
  625.         main_entry.focus_set()
  626.     result = str(get_result(input_list))

  627.     if varEntry0.get() != "错误":
  628.         input_list = [result]
  629.         # if varEntry0.get() != varEntry0.get():
  630.         varLabel0.set(varLabel0.get() + varEntry0.get())
  631.         varEntry0.set("=" + result)

  632.     main_entry.icursor(ttk.END)  # 光标移到最后


  633. def key_continue(i):
  634.     is_old_entry_part(txt=i, is_usual=False)


  635. # 显示结果部分

  636. varLabel0 = ttk.StringVar()
  637. varLabel0.set("计算过程区:")

  638. main_label = ttk.Label(win, font=("Open Sans", 15), textvariable=varLabel0)
  639. main_label.pack(fill="x")
  640. varEntry0 = ttk.StringVar()

  641. main_entry = ttk.Entry(win, font=("微软雅黑", 16), textvariable=varEntry0)
  642. # main_entry.grid_columnconfigure(0, weight=1)  # 设置第一列权重为1
  643. main_entry.pack(fill="x")
  644. # main_entry.bind("<Control-v>", lambda event: input_list.extend(main_entry.clipboard_get()))  # 绑定键盘事件
  645. # main_entry.bind("<Control-x>", lambda event: input_list.extend(main_entry.get()))  # 绑定键盘事件
  646. main_entry.bind("<Key>", lambda event: solve_key(event, disable=True))  # 禁用所有按钮
  647. # main_entry.bind("<Return>", lambda event: equal_click(is_key=True))  # 绑定键盘事件
  648. # main_entry.bind("<c>", lambda event: _clear())
  649. main_entry.focus_set()  # 开始时鼠标焦点在输入框,以便键入

  650. # 按钮部分
  651. # 创建frame框架
  652. box = ttk.Frame(win)
  653. box.pack(fill="x")

  654. # 按钮文本的列表
  655. btn_text_list = [["(", ")", "√x", "/", "&#739;√y", "sin x"],
  656.                  ["7", "8", "9", "*", "x&#696;",   "cos x"],
  657.                  ["4", "5", "6", "-", "取余",  "tan x"],
  658.                  ["1", "2", "3", "+", "整除",  "x!"],
  659.                  ["±", "0", ".", "CE", "AC",   "π"]]
  660. FC_list = [[0, 0], [0, 1], [0, 2],       [0, 4], [0, 5],
  661.            [1, 0],                 [1, 3],
  662.            [2, 0], [2, 1],         [2, 3],
  663.            [3, 0],                 [3, 3],
  664.            [4, 0],                       [4, 4], [4, 5]]
  665. '''
  666.     单击事件绑定
  667.         1.command只能绑定一个,如果要传参可以用lambda表达式
  668.         2.bind可以传当前控件事件到自定义函数
  669. '''
  670. # 行和列
  671. ri = 0
  672. ci = 0
  673. # 通过循环批量制作按钮
  674. for i in btn_text_list:
  675.     for each in i:
  676.         each = ttk.Button(box, text=each, width=4, style="warning-outline")
  677.         each.bind("<ButtonRelease-1>", calcu)  # 左键抬起事件
  678.         each.name = [ri, ci]
  679.         each.grid(row=ri, column=ci)
  680.         ci += 1
  681.     ri += 1
  682.     ci = 0


  683. def on_hover(event):
  684.     if FC_symbol:
  685.         for child in box.winfo_children():
  686.             if child.name in FC_list:
  687.                 child.config(style="danger.TButton")


  688. def on_leave(event):
  689.     if FC_symbol:
  690.         for child in box.winfo_children():
  691.             if child.name in FC_list:
  692.                 child.config(bootstyle="warning-outline")


  693. # =按钮
  694. pic_equal = Image.open("./equal_image.png")  # 载入图片对象
  695. pic_equal = pic_equal.resize((225, 60))  # 一个元组
  696. pic_equal = ImageTk.PhotoImage(pic_equal)  # 变成适合ttk的图片格式
  697. btn_equal = ttk.Button(win, image=pic_equal, command=equal_click, style="danger", name="btn_equal")
  698. # 绑定鼠标悬停和离开事件
  699. btn_equal.bind("<Enter>", on_hover)  # 鼠标进入按钮
  700. btn_equal.bind("<Leave>", on_leave)  # 鼠标离开按钮
  701. btn_equal.pack(fill="x")


  702. if __auther__ == "__sky__":  # 这句没有任何作用,冒充__name__ == "__main__"
  703.     win.mainloop()
复制代码


Last but not least
欢迎评分


FC.PNG
捕获2.PNG
捕获.PNG

评分

参与人数 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 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 8 小时前 | 显示全部楼层
记得替换成自己的主题
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 8 小时前 | 显示全部楼层
本帖最后由 某一个“天” 于 2025-7-5 10:55 编辑

@不二如是 @sfqxx @isdkz @zhangjinxuan @python爱好者. @小甲鱼的三师弟 @fishc.com @~风介~
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 8 小时前 | 显示全部楼层
@fishc.com @~风介~ @小甲鱼的二师兄 @player-none @py木木
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 8 小时前 | 显示全部楼层
@的名额不够了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 小时前 | 显示全部楼层

回帖奖励 +66 鱼币

居然还有音效?这你受得了!!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 小时前 | 显示全部楼层
小甲鱼 发表于 2025-7-5 12:10
居然还有音效?这你受得了!!

我去,咋中了这么大奖
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 6 小时前 | 显示全部楼层
小甲鱼 发表于 2025-7-5 12:10
居然还有音效?这你受得了!!

厉害,暗调概率
(甲鱼哥运气真好
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 5 小时前 | 显示全部楼层

回帖奖励 +11 鱼币

哇,大工程啊,厉害!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 5 小时前 | 显示全部楼层
这音效...
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 小时前 | 显示全部楼层
奋斗中的鱼 发表于 2025-7-5 13:48
哇,大工程啊,厉害!

评个分呗
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 3 小时前 From FishC Mobile | 显示全部楼层

回帖奖励 +11 鱼币

哇塞又更新了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层
期待!!!继续迭代升级
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 3 小时前 From FishC Mobile | 显示全部楼层
厉害!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 半小时前 | 显示全部楼层

回帖奖励 +11 鱼币

支持
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 25 分钟前 | 显示全部楼层

小号评个分呗
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-5 19:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表