"""
frame框架布局
在frame内部,可以重新进行一次布局
"""
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from PIL import ImageTk, Image
from decimal import Decimal
from math import sqrt
def top1():
top = ttk.Toplevel(title="详情")
label = ttk.Label(master=top, text="""
全FishC最好的计算器!\n
消除误差!0.1+0.2可以等于0.3!
过大或过小的数值会用科学计数法\n
注意:
π取3.1415926,根号运算取7位小数,
支持鼠标点击和键盘输入(非常神奇)
其中键盘输入 删除,回车,C,c 有奇效\n
还支持某些(奇怪)的运算,如:√√√256(就是2)
""")
label.pack()
def top2():
top = ttk.Toplevel(title="作者")
label = ttk.Label(master=top, text="""
作者:FishC 某一个“天”
~谢谢使用~
""")
label.pack()
def top3():
top = ttk.Toplevel(title="历史记录")
label = ttk.Label(master=top, text="".join(history_input_list))
label.pack()
win = ttk.Window()
win.title("FishC最好的?计算器")
win.geometry("360x364+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)
style = ttk.Style()
style.configure("TButton", font=("微软雅黑", 15))
history_input_list = []
input_list = []
def my_sqrt(x):
return Decimal(Decimal(sqrt(x))).quantize(Decimal("0.0000000"))
def clear():
input_list.clear()
varLabel0.set("计算过程区:")
varEntry0.set("")
def is_old_entry_part(txt):
global input_list
if "=" in varEntry0.get() or varEntry0.get() == "错误": # 新的算式
input_list = [txt]
varLabel0.set("计算过程区:")
varEntry0.set(txt)
return False
return True
def calcu(event, is_key=False):
global input_list
# 判断输入方式
if is_key:
txt = event.char
print("-------", txt)
if txt == "\x08": # 删除键
input_list = input_list[:-1]
elif txt == "\r": # 回车键
varLabel0.set("")
theEqual_Click()
elif txt in ("c", "C"): # 清空
clear()
return "break" # 取消本次输入
else:
if is_old_entry_part(txt):
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 = "√"
if txt == "00":
input_list.append("0")
input_list.append("0")
else:
input_list.append(txt)
print(input_list)
def fast_add(master, text=txt):
master.set(master.get() + text)
# 防止输入过长
if len(varEntry0.get()) < 28 or txt == "C" or txt == "CE":
if txt == "C": # 清空
clear()
elif txt == "CE":
del input_list[-2:]
if varEntry0.get() and "=" not in varEntry0.get():
if varEntry0.get()[-2:] in ("**", "//"):
varEntry0.set(varEntry0.get()[:-2])
else:
varEntry0.set(varEntry0.get()[:-1])
elif "=" not in varEntry0.get():
if varLabel0.get()[-2:] in ("**", "//"):
varLabel0.set(varLabel0.get()[:-2])
else:
varLabel0.set(varLabel0.get()[:-1])
elif txt == "π":
try:
if is_old_entry_part(txt):
fast_add(varEntry0)
# 有 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 == "√":
if is_old_entry_part(txt):
fast_add(varEntry0)
elif txt in ("+", "-", "*", "/", "%", "//", "**"):
if "=" in varEntry0.get():
input_list = [get_result(input_list[:-1])]
varEntry0.set("")
varLabel0.set(get_result(input_list) + txt)
input_list.append(txt)
elif ("+" in varLabel0.get() or "-" in varLabel0.get() or
"*" in varLabel0.get() or "/" in varLabel0.get() or
"%" in varLabel0.get() or "//" in varLabel0.get() or
"**" in varLabel0.get()):
# 考虑到运算顺序
if (txt in ("+", "-") or "**" in varEntry0.get()) and "(" not in varEntry0.get():
try:
res = get_result(input_list[:-1])
varLabel0.set(res + txt)
input_list = [res, txt]
varEntry0.set("")
except Exception as e:
print(e)
input_list.pop() # 删掉错误信息
varEntry0.set("错误")
else:
varLabel0.set(varLabel0.get() + varEntry0.get() + txt)
varEntry0.set("")
else:
if "(" in varEntry0.get() and ")" not in varEntry0.get(): # 分行
fast_add(varEntry0) # 正常输入
else:
if "√" in varEntry0.get():
varEntry0.set(get_result(input_list[:-1]) + txt)
else:
varLabel0.set(varEntry0.get() + txt)
varEntry0.set("")
else:
if is_old_entry_part(txt):
fast_add(varEntry0) # 正常输入数字的情况
def split_list(lst, *delimiter):
result = []
current_part = []
have_right_bracket = 0
for item in lst:
if item == ")":
have_right_bracket += 1
elif item == "√":
current_part.append("my_sqrt(")
have_right_bracket += 1
elif item == "π":
current_part.append("3.1415926")
if item in delimiter:
if current_part: # 确保当前部分不为空
result.append(current_part)
current_part = []
while have_right_bracket and item != "(":
result.append(")")
have_right_bracket -= 1
result.append(item)
# 可能出现在开头的
elif item in ("-", "("):
result.append(item)
elif item not in ("√", ")", "π"):
current_part.append(item)
if current_part: # 添加最后一部分(如果存在)
while have_right_bracket:
current_part.append(")")
have_right_bracket -= 1
result.append(current_part)
return result
def get_result(lst):
split_result = split_list(lst, "(", "+", "-", "*", "/", "%", "//", "**")
split_result = ["".join(i) for i in split_result]
index = 0
for each in split_result:
try:
split_result[index] = repr(Decimal(each))
except Exception as e:
print(e)
print(split_result)
index += 1
result = str(eval("".join(split_result)))
history_input_list.extend(["".join(input_list), "=", result, "\n"])
return result
def theEqual_Click():
try:
result = get_result(input_list)
print(result)
varLabel0.set(varLabel0.get()+varEntry0.get())
varEntry0.set("=" + result)
except Exception as e:
print(e)
varEntry0.set("错误")
# 显示结果部分
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)
# 按钮文本的列表
btnText = ["(", ")", "x^y", "√x", "π",
"7", "8", "9", "*", "/",
"4", "5", "6", "+", "-",
"1", "2", "3", "取余", "整除",
"0", "00", ".", "C", "CE"]
# 行和列
ri = 0
ci = 0
# 通过循环批量制作按钮
for v in btnText:
if ci != 0 and ci % 5 == 0:
ri += 1 # 换行
ci = 0 # 列变为0
'''单击事件绑定
1.command只能绑定一个,如果要传参可以用lambda表达式
2.bind可以传当前控件事件到自定义函数'''
btn1 = ttk.Button(box, text=v, width=4, bootstyle=(SUCCESS, OUTLINE))
btn1.bind("<Button-1>", calcu) # 左键单击事件
btn1.grid(row=ri, column=ci, rowspan=1)
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=theEqual_Click, style='warning-solid')
btnEqual.grid(row=ri + 1, column=0, columnspan=5, sticky=ttk.EW)
win.mainloop()