|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
上期作品
熟悉我的都知道啊,这计算器已经迭代多次了。不浪费大家时间,只放一个上次的,有兴趣可以看看
0.1+0.2可以等于0.3!全FishC最好的计算器(不是),满足你对计算器的一切幻想 https://fishc.com.cn/thread-245235-1-1.html (出处: 鱼C论坛)]0.1+0.2可以等于0.3!全FishC最好的计算器
本期介绍
@isdkz @zhangjinxuan @sfqxx @不二如是 @python爱好者. @ba21 @KeyError @python爱好者. @小甲鱼的三师弟 @~风介~ @小甲鱼的二师兄 @鱼小二
可以注意到很多区别
全FishC最好的计算器!
消除误差!0.1+0.2可以等于0.3!
过大或过小的数值会用科学计数法
任选角度测量制度(默认角度制)
注意:
阶乘 ! 是括号之下优先级最高的运算
算术平方根运算后不加括号将只算数字
小数点后取7位(可调整),采用银行家舍入
【四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一】
支持鼠标点击和键盘输入(非常神奇),但尽量不要混合使用
其中键盘输入 删除,回车,C有奇效。
输入0b, 0o, 0x前缀后回车或点击“=”可以转换为十进制。计算的十进制结果可直接转换进制
还支持某些(奇怪)运算,如:√√√√65536(就是2),3!!(720)
甚至还可以动态调整运算精度
完整代码
- """frame框架布局
- 在frame内部,可以重新进行一次布局"""
- 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
- use_big = True
- angle_set = "角度制"
- digits_after_point = 7
- def resize_window():
- global use_big
- step = 0
- def worker(u_big):
- nonlocal step
- if u_big:
- win.geometry(f"{432-step}x344")
- step += 24
- if step == 72:
- btnEqual.grid(row=ri + 1, column=0, columnspan=5, sticky=ttk.EW)
- elif step == 144:
- btnEqual.grid(row=ri + 1, column=0, columnspan=4, sticky=ttk.EW)
- if step <= 144:
- print(step)
- win.after(20, worker, u_big)
- else:
- win.geometry(f"{288 + step}x344")
- step += 24
- if step == 72:
- btnEqual.grid(row=ri + 1, column=0, columnspan=5, sticky=ttk.EW)
- elif step == 144:
- btnEqual.grid(row=ri + 1, column=0, columnspan=6, sticky=ttk.EW)
- if step <= 144:
- print(step)
- win.after(20, worker, u_big)
- worker(use_big)
- use_big = not use_big
- def like_ago():
- global angle_set, digits_after_point
- angle_set = "角度制"
- digits_after_point = 7
- def top1():
- top = ttk.Toplevel(title="详情")
- label = ttk.Label(master=top, text="""
- 全FishC最好的计算器!
-
- 消除误差!0.1+0.2可以等于0.3!
- 过大或过小的数值会用科学计数法
- 任选角度测量制度(默认角度制)
- 注意:
- 阶乘 ! 是括号之下优先级最高的运算
- 算术平方根运算后不加括号将只算数字
- 小数点后取7位(可调整),采用银行家舍入
- 【四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一】
- 支持鼠标点击和键盘输入(非常神奇),但尽量不要混合使用
- 其中键盘输入 删除,回车,C有奇效。
- 输入0b, 0o, 0x前缀后回车或点击“=”可以转换为十进制。计算的十进制结果可直接转换进制
- 还支持某些(奇怪)运算,如:√√√√65536(就是2),3!!(720)
- 甚至还可以动态调整运算精度
- """,
- font=("楷体", 14))
- label.pack()
- def top2():
- top = ttk.Toplevel(title="作者")
- label = ttk.Label(master=top,
- text="""作者:FishC 某一个“天”
- ~谢谢使用~""",
- font=14)
- label.pack()
- def top3():
- top = ttk.Toplevel(title="历史记录")
- label = ttk.Label(master=top, text="".join(history_input_list), font=("微软雅黑", 12))
- label.pack()
- def top4():
- def write_change():
- history_input_list.append(f"记录!角度测量制度是<{rVar.get()}>\n")
- history_input_list.append(f"记录!小数点后取<{digits_after_point}>位\n")
- top.destroy()
- def digits_changed(x):
- global digits_after_point
- digits_after_point = int(float(x))
- print("now222:", digits_after_point)
- valueVar.set(f"1 小数点后取{digits_after_point}位 15")
- def angle_changed():
- global angle_set
- angle_set = rVar.get()
- top = ttk.Toplevel(title="设置")
- global digits_after_point, angle_set
- valueVar = ttk.StringVar()
- valueVar.set(f"1 小数点后取{digits_after_point}位 15")
- l1 = ttk.Label(top, textvariable=valueVar, foreground="green", font=8)
- l1.pack()
- sc1 = ttk.Scale(top, length=200, from_=1, to=15, value=digits_after_point, style="TScale",
- command=lambda val: digits_changed(val))
- sc1.pack()
- l2 = ttk.Label(top, text="角度测量制度", foreground="purple", font=8)
- l2.pack(pady=10)
- rVar = ttk.StringVar()
- rVar.set(angle_set) # 开始时选中角度制
- r1 = ttk.Radiobutton(top, text="角度制", value="角度制", variable=rVar, command=angle_changed)
- r1.pack()
- r2 = ttk.Radiobutton(top, text="弧度制", value="弧度制", variable=rVar, command=angle_changed)
- r2.pack()
- l2 = ttk.Label(top, text="*设置无需记录即可生效\n记录后可在历史记录中找到", foreground="red")
- l2.pack(pady=10)
- write_btn = ttk.Button(top, text="记录到历史", command=write_change, style="success")
- write_btn.pack(pady=10)
- win = ttk.Window()
- win.title("FishC最好的?计算器")
- win.geometry("432x364+500+200")
- win.resizable(width=False, height=False) # 设置不能调整窗口大小
- # 设置窗体图标
- win.iconbitmap("./py_pic/jsq3.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"得数转为十六进制是{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=like_ago)
- control_menu.add_command(label="使用精简版/科学版", command=resize_window)
- menu_bar.add_cascade(label="设置", menu=control_menu)
- main_style = ttk.Style()
- main_style.configure("TButton", font=("微软雅黑", 15))
- main_style.configure('TScale', sliderlength=30, sliderthickness=20, troughcolor='#D3D3D3', background='#FFFFFF')
- input_list = []
- history_input_list = []
- def my_factorial(x):
- try:
- print("fun:", x)
- return factorial(int(x))
- except Exception as e:
- print(e)
- varEntry0.set("错误")
- def my_sqrt(x):
- return Decimal(sqrt(x))
- def my_sin(x):
- if angle_set == "角度制":
- angle_in_radians = radians(x)
- return Decimal(sin(angle_in_radians))
- else:
- return Decimal(sin(x))
- def my_cos(x):
- if angle_set == "角度制":
- angle_in_radians = radians(x)
- return Decimal(cos(angle_in_radians))
- else:
- return Decimal(cos(x))
- def my_tan(x):
- if angle_set == "角度制":
- angle_in_radians = radians(x)
- return Decimal(tan(angle_in_radians))
- else:
- return Decimal(tan(x))
- def calcu(event, is_key=False):
- global input_list
- if varLabel0.get() == "计算过程区:":
- varLabel0.set("")
- def history_separate():
- history_input_list.append("---------------------------------\n")
- def clear():
- if len(input_list) > 1: # 除了C之外还有别的
- history_separate()
- input_list.clear()
- varLabel0.set("计算过程区:")
- varEntry0.set("")
- def is_old_entry_part(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 fast_add(master, text):
- master.set(master.get() + text)
- # 判断输入方式
- if is_key:
- txt = event.char
- print("-------", txt)
- if txt == "\x08": # 删除键
- input_list = input_list[:-1]
- elif txt == "\r": # 回车键
- varLabel0.set("")
- equal_click()
- elif txt == "C": # 清空
- clear()
- return "break" # 取消本次输入
- elif txt in ("π", "("):
- try:
- if is_old_entry_part():
- # 有 IndexError: list index out of range 的危险
- if input_list[-2] in ("π", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
- input_list.append("*")
- input_list.append(txt)
- except Exception as e:
- print(e)
- else:
- if len(varEntry0.get()) > 30:
- varEntry0.set(varEntry0.get()[:30])
- else:
- if is_old_entry_part():
- input_list.append(txt)
- else:
- txt = str(event.widget["text"])
- if txt == "取余":
- txt = "%"
- elif txt == "整除":
- txt = "//"
- elif txt == "x^y":
- txt = "^"
- elif txt == "√x":
- txt = "√"
- elif txt == "x!":
- txt = "!"
- elif txt == "sin x":
- txt = "sin"
- elif txt == "cos x":
- txt = "cos"
- elif txt == "tan x":
- txt = "tan"
- if txt == "+/-":
- is_old_entry_part(False)
- if varEntry0.get()[0] == "-":
- varEntry0.set(varEntry0.get()[1:])
- input_list.reverse()
- input_list.remove("-")
- input_list.reverse()
- 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(")")
- x = 0
- for i in range(len(input_list)):
- if input_list[::-1][i] == "(":
- _ += 1
- if _ == n:
- only_fact = False
- x = len(input_list) - i - 1
- break
- elif input_list[::-1][i] in ("+", "-", "*", "/", "%", "//", "^"):
- only_fact = False
- x = len(input_list) - i
- if _ >= n:
- break
- if only_fact:
- input_list.insert(0, "!")
- else:
- input_list[x:x] = ["!"]
- else:
- input_list.append(txt)
- # 防止输入过长
- if (len(varEntry0.get()) < 26 or txt == "C" or txt == "CE") and txt != "+/-":
- if txt == "C": # 清空
- clear()
- elif txt == "CE":
- print("get", varEntry0.get())
- if "=" not in varEntry0.get(): # 不能删除得数
- input_list.pop() # 把CE删掉
- if varEntry0.get() == "错误":
- varEntry0.set("")
- 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 ("π", "√", "("):
- try:
- if is_old_entry_part():
- 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))
- print("添加后", 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 "√" in varEntry0.get() and txt != "*":
- varEntry0.set(get_result(input_list[:-1]) + txt)
- elif txt == "-" and input_list[0] == "-" and input_list.count("-") == 1: # 负号而不是减号
- if is_old_entry_part():
- fast_add(varEntry0, txt) # 正常输入
- else:
- varLabel0.set(varEntry0.get() + txt)
- varEntry0.set("")
- else:
- if is_old_entry_part():
- fast_add(varEntry0, txt) # 正常输入数字的情况
- def split_list(lst, *delimiter):
- result = []
- current_part = []
- have_right_bracket = 0
- for item in lst:
- if 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 not in ("√", ")", "π", "!"):
- 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, is_eq_click=False):
- 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)
- print(each)
- print(splited_result)
- index += 1
- try:
- print("WHYYYYYYYYYYYYY", splited_result)
- result = eval("".join(splited_result))
- except Exception as e: # 可能由各种原因导致
- print("?????????", e)
- varEntry0.set("错误")
- result = str(result)
- try:
- 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) >= 26:
- result = f"{Decimal(result):.{digits_after_point}e}"
- if is_eq_click:
- history_input_list.extend([varLabel0.get()+varEntry0.get(), "=", result, "\n"])
- return result
- def equal_click():
- global input_list
- result = str(get_result(input_list, True))
- if varEntry0.get() == "错误":
- input_list = input_list[:-1]
- else:
- input_list = [result]
- varLabel0.set(varLabel0.get() + varEntry0.get())
- varEntry0.set("=" + result)
- # 显示结果部分
- varLabel0 = ttk.StringVar()
- varLabel0.set("计算过程区:")
- label0 = ttk.Label(win, font=("宋体", 15), textvariable=varLabel0)
- label0.grid(sticky=ttk.EW) # 东西方向填充
- varEntry0 = ttk.StringVar()
- entry0 = ttk.Entry(win, font=("微软雅黑", 15), textvariable=varEntry0)
- entry0.grid(sticky=ttk.EW) # 东西方向填充
- entry0.bind("<Key>", lambda event: calcu(event, True)) # 绑定键盘事件
- # 按钮部分
- # 创建frame框架
- box = ttk.Frame(win)
- box.grid(row=2, column=0)
- # 按钮文本的列表
- btn_text = ["(", ")", "x^y", "/", "π", "sin x",
- "7", "8", "9", "*", "√x", "cos x",
- "4", "5", "6", "-", "取余", "tan x",
- "1", "2", "3", "+", "整除", "x!",
- "0", ".", "+/-", "CE", "C"]
- # 行和列
- ri = 0
- ci = 0
- # 通过循环批量制作按钮
- for v in btn_text:
- if ci != 0 and ci % 6 == 0:
- ri += 1 # 换行
- ci = 0 # 列变为0
- '''单击事件绑定
- 1.command只能绑定一个,如果要传参可以用lambda表达式
- 2.bind可以传当前控件事件到自定义函数'''
- btn1 = ttk.Button(box, text=v, width=4, style="warning-outline")
- btn1.bind("<Button-1>", calcu) # 左键单击事件
- if ri == 4 and ci == 0:
- btn1.config(width=10)
- btn1.grid(row=ri, column=ci, columnspan=2)
- ci += 2
- else:
- btn1.grid(row=ri, column=ci)
- ci += 1
- # =按钮
- pic_equal = Image.open("./py_pic/等于号.png") # 载入图片对象
- pic_equal = pic_equal.resize((225, 60)) # 一个元组
- pic_equal = ImageTk.PhotoImage(pic_equal) # 变成适合ttk的图片格式
- btnEqual = ttk.Button(box, image=pic_equal, command=equal_click, style='danger-solid')
- btnEqual.grid(row=ri + 1, column=0, columnspan=6, sticky=ttk.EW)
- win.mainloop()
复制代码
未来前景
打算加上视觉识别,扩充功能
大家发现 bug ,有建议可以提出!
不要吝啬评分
|
评分
-
查看全部评分
|