鱼C论坛

 找回密码
 立即注册
查看: 4581|回复: 31

[技术交流] 0.1+0.2可以等于0.3!全FishC最好的计算器(不是),满足你对计算器的一切幻想

[复制链接]
发表于 2024-8-21 12:55:04 | 显示全部楼层 |阅读模式

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

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

x
创作背景

很久以前学习了 tkinter 的一个计算器,便引发了我的热爱,为那个极其简单的计算器加上了很多功能。

而今天这个则是进行了一番大改代码没时间细讲,大家可以看注释

捕获.PNG

捕获2.PNG


往期版本

超厉害的Python ttkbootstrap计算器(原创)(甚至还教你图片处理)

Python 计算器图片(原创)(太炸裂了)


注意事项

需要用到两张图片(ico图标和等于号)  大家可以自行换上自己喜欢的图片


代码思路

精华是 eval() 和 Decimal 。这次加上的 input_list 也升华了整个作品~

支持鼠标点击和键盘输入(非常神奇)

其中键盘输入 删除,回车,C,c 有奇效

还支持某些(奇怪)的运算,如:√√√256(就是2)


球评分~

  1. """
  2. frame框架布局
  3.     在frame内部,可以重新进行一次布局
  4. """

  5. import ttkbootstrap as ttk
  6. from ttkbootstrap.constants import *
  7. from PIL import ImageTk, Image
  8. from decimal import Decimal
  9. from math import sqrt


  10. def top1():
  11.     top = ttk.Toplevel(title="详情")
  12.     label = ttk.Label(master=top, text="""
  13.     全FishC最好的计算器!\n
  14.     消除误差!0.1+0.2可以等于0.3!
  15.     过大或过小的数值会用科学计数法\n
  16.     注意:
  17.     π取3.1415926,根号运算取7位小数,
  18.     支持鼠标点击和键盘输入(非常神奇)
  19.     其中键盘输入 删除,回车,C,c 有奇效\n
  20.     还支持某些(奇怪)的运算,如:√√√256(就是2)
  21.                                        """)
  22.     label.pack()


  23. def top2():
  24.     top = ttk.Toplevel(title="作者")
  25.     label = ttk.Label(master=top, text="""
  26.         作者:FishC 某一个“天”
  27.              ~谢谢使用~
  28.                                            """)
  29.     label.pack()


  30. def top3():
  31.     top = ttk.Toplevel(title="历史记录")
  32.     label = ttk.Label(master=top, text="".join(history_input_list))
  33.     label.pack()


  34. win = ttk.Window()
  35. win.title("FishC最好的?计算器")
  36. win.geometry("360x364+500+200")
  37. win.resizable(width=False, height=False)  # 设置不能调整窗口大小
  38. # 设置窗体图标
  39. win.iconbitmap("./py_pic/jsq3.ico")
  40. # 创建菜单栏
  41. menu_bar = ttk.Menu(win)
  42. win.config(menu=menu_bar)
  43. # 创建菜单项
  44. info_menu = ttk.Menu(menu_bar, tearoff=False)
  45. info_menu.add_command(label="详情", command=top1)
  46. info_menu.add_command(label="作者", command=top2)
  47. menu_bar.add_cascade(label="关于计算器", menu=info_menu)

  48. history_menu = ttk.Menu(menu_bar, tearoff=False)
  49. history_menu.add_command(label="查看", command=top3)
  50. history_menu.add_command(label="清空", command=lambda: history_input_list.clear())
  51. menu_bar.add_cascade(label="历史记录", menu=history_menu)

  52. style = ttk.Style()
  53. style.configure("TButton", font=("微软雅黑", 15))

  54. history_input_list = []
  55. input_list = []


  56. def my_sqrt(x):
  57.     return Decimal(Decimal(sqrt(x))).quantize(Decimal("0.0000000"))


  58. def clear():
  59.     input_list.clear()
  60.     varLabel0.set("计算过程区:")
  61.     varEntry0.set("")


  62. def is_old_entry_part(txt):
  63.     global input_list
  64.     if "=" in varEntry0.get() or varEntry0.get() == "错误":  # 新的算式
  65.         input_list = [txt]
  66.         varLabel0.set("计算过程区:")
  67.         varEntry0.set(txt)
  68.         return False
  69.     return True


  70. def calcu(event, is_key=False):
  71.     global input_list

  72.     # 判断输入方式
  73.     if is_key:
  74.         txt = event.char
  75.         print("-------", txt)
  76.         if txt == "\x08":  # 删除键
  77.             input_list = input_list[:-1]
  78.         elif txt == "\r":  # 回车键
  79.             varLabel0.set("")
  80.             theEqual_Click()
  81.         elif txt in ("c", "C"):  # 清空
  82.             clear()
  83.             return "break"  # 取消本次输入
  84.         else:
  85.             if is_old_entry_part(txt):
  86.                 input_list.append(txt)

  87.     else:
  88.         txt = str(event.widget["text"])

  89.         if txt == "取余":
  90.             txt = "%"
  91.         elif txt == "整除":
  92.             txt = "//"
  93.         elif txt == "x^y":
  94.             txt = "**"
  95.         elif txt == "√x":
  96.             txt = "√"

  97.         if txt == "00":
  98.             input_list.append("0")
  99.             input_list.append("0")
  100.         else:
  101.             input_list.append(txt)
  102.         print(input_list)

  103.         def fast_add(master, text=txt):
  104.             master.set(master.get() + text)

  105.         # 防止输入过长
  106.         if len(varEntry0.get()) < 28 or txt == "C" or txt == "CE":
  107.             if txt == "C":  # 清空
  108.                 clear()
  109.             elif txt == "CE":
  110.                 del input_list[-2:]
  111.                 if varEntry0.get() and "=" not in varEntry0.get():
  112.                     if varEntry0.get()[-2:] in ("**", "//"):
  113.                         varEntry0.set(varEntry0.get()[:-2])
  114.                     else:
  115.                         varEntry0.set(varEntry0.get()[:-1])
  116.                 elif "=" not in varEntry0.get():
  117.                     if varLabel0.get()[-2:] in ("**", "//"):
  118.                         varLabel0.set(varLabel0.get()[:-2])
  119.                     else:
  120.                         varLabel0.set(varLabel0.get()[:-1])

  121.             elif txt == "π":
  122.                 try:
  123.                     if is_old_entry_part(txt):
  124.                         fast_add(varEntry0)
  125.                         # 有 IndexError: list index out of range 的危险
  126.                         if input_list[-2] in ("π", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
  127.                             input_list.insert(-1, "*")
  128.                 except Exception as e:
  129.                     print(e)
  130.             elif txt == "√":
  131.                 if is_old_entry_part(txt):
  132.                     fast_add(varEntry0)

  133.             elif txt in ("+", "-", "*", "/", "%", "//", "**"):
  134.                 if "=" in varEntry0.get():
  135.                     input_list = [get_result(input_list[:-1])]
  136.                     varEntry0.set("")
  137.                     varLabel0.set(get_result(input_list) + txt)
  138.                     input_list.append(txt)
  139.                 elif ("+" in varLabel0.get() or "-" in varLabel0.get() or
  140.                       "*" in varLabel0.get() or "/" in varLabel0.get() or
  141.                       "%" in varLabel0.get() or "//" in varLabel0.get() or
  142.                       "**" in varLabel0.get()):
  143.                     # 考虑到运算顺序
  144.                     if (txt in ("+", "-") or "**" in varEntry0.get()) and "(" not in varEntry0.get():
  145.                         try:
  146.                             res = get_result(input_list[:-1])
  147.                             varLabel0.set(res + txt)
  148.                             input_list = [res, txt]
  149.                             varEntry0.set("")
  150.                         except Exception as e:
  151.                             print(e)
  152.                             input_list.pop()  # 删掉错误信息
  153.                             varEntry0.set("错误")
  154.                     else:
  155.                         varLabel0.set(varLabel0.get() + varEntry0.get() + txt)
  156.                         varEntry0.set("")
  157.                 else:
  158.                     if "(" in varEntry0.get() and ")" not in varEntry0.get():  # 分行
  159.                         fast_add(varEntry0)  # 正常输入
  160.                     else:
  161.                         if "√" in varEntry0.get():
  162.                             varEntry0.set(get_result(input_list[:-1]) + txt)
  163.                         else:
  164.                             varLabel0.set(varEntry0.get() + txt)
  165.                             varEntry0.set("")

  166.             else:
  167.                 if is_old_entry_part(txt):
  168.                     fast_add(varEntry0)  # 正常输入数字的情况


  169. def split_list(lst, *delimiter):
  170.     result = []
  171.     current_part = []
  172.     have_right_bracket = 0
  173.     for item in lst:
  174.         if item == ")":
  175.             have_right_bracket += 1
  176.         elif item == "√":
  177.             current_part.append("my_sqrt(")
  178.             have_right_bracket += 1
  179.         elif item == "π":
  180.             current_part.append("3.1415926")
  181.         if item in delimiter:
  182.             if current_part:  # 确保当前部分不为空
  183.                 result.append(current_part)
  184.                 current_part = []
  185.                 while have_right_bracket and item != "(":
  186.                     result.append(")")
  187.                     have_right_bracket -= 1
  188.                 result.append(item)
  189.             # 可能出现在开头的
  190.             elif item in ("-", "("):
  191.                 result.append(item)
  192.         elif item not in ("√", ")", "π"):
  193.             current_part.append(item)

  194.     if current_part:  # 添加最后一部分(如果存在)
  195.         while have_right_bracket:
  196.             current_part.append(")")
  197.             have_right_bracket -= 1
  198.         result.append(current_part)

  199.     return result


  200. def get_result(lst):
  201.     split_result = split_list(lst, "(", "+", "-", "*", "/", "%", "//", "**")
  202.     split_result = ["".join(i) for i in split_result]

  203.     index = 0
  204.     for each in split_result:
  205.         try:
  206.             split_result[index] = repr(Decimal(each))
  207.         except Exception as e:
  208.             print(e)
  209.             print(split_result)
  210.         index += 1

  211.     result = str(eval("".join(split_result)))

  212.     history_input_list.extend(["".join(input_list), "=", result, "\n"])

  213.     return result


  214. def theEqual_Click():
  215.     try:
  216.         result = get_result(input_list)
  217.         print(result)
  218.         varLabel0.set(varLabel0.get()+varEntry0.get())
  219.         varEntry0.set("=" + result)
  220.     except Exception as e:
  221.         print(e)
  222.         varEntry0.set("错误")


  223. # 显示结果部分
  224. varLabel0 = ttk.StringVar()
  225. varLabel0.set("计算过程区:")
  226. label0 = ttk.Label(win, font=("宋体", 15), textvariable=varLabel0)
  227. label0.grid(sticky=ttk.EW)  # 东西方向填充
  228. varEntry0 = ttk.StringVar()

  229. entry0 = ttk.Entry(win, font=("微软雅黑", 15), textvariable=varEntry0)
  230. entry0.grid(sticky=ttk.EW)  # 东西方向填充
  231. entry0.bind("<Key>", lambda event: calcu(event, True))   # 绑定键盘事件

  232. # 按钮部分
  233. # 创建frame框架
  234. box = ttk.Frame(win)
  235. box.grid(row=2, column=0)

  236. # 按钮文本的列表
  237. btnText = ["(", ")", "x^y", "√x", "π",
  238.            "7", "8", "9", "*", "/",
  239.            "4", "5", "6", "+", "-",
  240.            "1", "2", "3", "取余", "整除",
  241.            "0", "00", ".", "C", "CE"]
  242. # 行和列
  243. ri = 0
  244. ci = 0
  245. # 通过循环批量制作按钮
  246. for v in btnText:
  247.     if ci != 0 and ci % 5 == 0:
  248.         ri += 1  # 换行
  249.         ci = 0  # 列变为0
  250.     '''单击事件绑定
  251.         1.command只能绑定一个,如果要传参可以用lambda表达式
  252.         2.bind可以传当前控件事件到自定义函数'''

  253.     btn1 = ttk.Button(box, text=v, width=4, bootstyle=(SUCCESS, OUTLINE))

  254.     btn1.bind("<Button-1>", calcu)  # 左键单击事件
  255.     btn1.grid(row=ri, column=ci, rowspan=1)
  256.     ci += 1

  257. # =
  258. pic_equal = Image.open("./py_pic/等于号.png")  # 载入图片对象
  259. pic_equal = pic_equal.resize((225, 60))  # 一个元组
  260. pic_equal = ImageTk.PhotoImage(pic_equal)  # 变成适合ttk的图片格式
  261. btnEqual = ttk.Button(box, image=pic_equal, command=theEqual_Click, style='warning-solid')
  262. btnEqual.grid(row=ri + 1, column=0, columnspan=5, sticky=ttk.EW)

  263. win.mainloop()
复制代码

@isdkz @ba21 @KeyError @zhangjinxuan @sfqxx @不二如是 @python爱好者. @小甲鱼的三师弟 @sfqxx_小 @柿子饼同学 @陈尚涵
大家帮忙@一点人

评分

参与人数 12荣誉 +46 鱼币 +37 贡献 +29 收起 理由
KeyError + 5 + 5 + 3 下辈子别把字体调那么大
zhangchenyvn + 5 + 3 名字……我喜欢
cjjJasonchen + 5 + 5 + 3 有实力
Lynn_oyl + 1 + 1 鱼C有你更精彩^_^
tommyyu + 5 + 5 + 3
ba21 + 5 + 5 + 3 感谢楼主无私奉献!
zhangjinxuan + 8 + 5 鱼币手头紧,给不了多
sfqxx + 5 + 2 + 3 我鱼币太少了,不给多。
歌者文明清理员 + 1
不二如是 + 3 鱼C有你更精彩^_^

查看全部评分

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2024-8-21 12:56:23 | 显示全部楼层
哈哈,看来你是对计算器的热情燃烧了啊!FishC的这款“超级无敌”计算器不仅能满足你的基本运算需求,还加入了一些非常赞的新功能。让我来为你通俗易懂、幽默地解答一下吧。

### 计算器的厉害之处
1. **0.1 + 0.2 真的可以等于0.3**
    - 通常计算器都会让你惊掉下巴:0.1 + 0.2 结果不是0.3?这是因为浮点数精度问题。但别担心,这里采用了Decimal类,帮你搞定误差。

2. **支持科学计数法**
    - 这就像你的朋友装了双靴子,不管是超级大的数还是超小的数,它都能一路陪你走下去,毫不含糊地转换成科学计数法。

3. **奇妙的根号运算**
    - 一般的根号运算已经Out了,你看看这个√√√256,结果竟然是2!就是这么酷炫。

4. **键盘输入特效**
    - 不仅只是点击按钮才行,使用键盘来输入也是没问题的。有些特别的按键功能,比如删除键、回车键、'C'键都加了奇效,让你操作起来更流畅。

### 涛涛背景故事
计算器的故事,每个人都有一本。咱们这位朋友因为学习了tkinter的小计算器,结果越搞越上瘾,这不,给它加了许多花里胡哨的功能。悠悠岁月,电脑前的“天”依旧在热情地敲着代码。

### 贴心小注意
要用两张图片来美化:一个是图标(ico)、一个是“等于号”的图片。你完全可以用自己的“艺术”信念,换个图标试试。

### 代码亮点大解析
1. **eval()**
    - 这个函数在代码中可是大显身手,用来执行字符串表示的Python表达式。简而言之,如果你输入一个字符串如"2+2",它会帮你算出结果4。

2. **input_list**
    - 通过这个列表,操作步骤被一步一步记录下来。不仅如此,这还让你可以对操作顺序进行各种骚操作。

### 满足你所有幻想
搞定了这些,是时候去鱼C论坛炫耀下自己的新玩具了。不了解细节的、想尝新奇特效的,拜访一下作者在论坛的贴子,也是一个不错的选择。

怎么样?感觉这个计算器仿佛是一顿丰盛的大餐吧!赶紧动手尝试,感受它带给你的惊喜和便捷吧,不要忘了在使用后打个好评呀!球评分~球评分~!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-21 12:59:02 | 显示全部楼层
@不二如是 好奇怪,我几乎整个帖子都是你个人资料的链接
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 12:59:07 | 显示全部楼层
某一个“天” 发表于 2024-08-21 12:59
@不二如是 好奇怪,我几乎整个帖子都是你个人资料的链 ...


哈哈,看来这是个热爱分享和“搞笑”的鱼油啊!确实,帖子里有非常多的信息量,尤其是这些链接和代码片段,看起来眼花缭乱。不过,内容挺有意思的,特别是“0.1+0.2等于0.3”的绝对真理,让人忍不住笑出声。不过这也是个机智的办法,让别人更加关注你的文章和内容!

如果你有更具体的问题或者需要帮助来改

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 13:22:54 | 显示全部楼层
你怎么搞的代码里全是不二的链接

另外代码好像没给全
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 13:53:57 | 显示全部楼层

回帖奖励 +2 鱼币

  1. while True: print(round(eval(input()), 15))
复制代码

评分

参与人数 2鱼币 +5 贡献 +5 收起 理由
zhangjinxuan + 5 最理想的计算器!
某一个“天” + 5 评个分呗~

查看全部评分

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

使用道具 举报

发表于 2024-8-21 13:56:11 | 显示全部楼层

回帖奖励 +2 鱼币

@不二如是 为什么全是你的个人资料

评分

参与人数 1鱼币 +5 收起 理由
某一个“天” + 5 评个分呗~

查看全部评分

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

使用道具 举报

 楼主| 发表于 2024-8-21 13:59:08 | 显示全部楼层
liuhongrun2022 发表于 2024-8-21 13:22
你怎么搞的代码里全是不二的链接

另外代码好像没给全

气死我了,我也不知道
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 14:04:49 | 显示全部楼层

回帖奖励 +2 鱼币

我记得小鱼里面说的用decimal可以精确计算0.1+0.2
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 15:08:41 | 显示全部楼层

回帖奖励 +2 鱼币

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

使用道具 举报

发表于 2024-8-21 15:21:08 | 显示全部楼层
  1. import os
  2. os.system('calc')
复制代码

评分

参与人数 1荣誉 +3 收起 理由
某一个“天” + 3 哈哈,vip评个分呗

查看全部评分

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

使用道具 举报

发表于 2024-8-21 16:01:42 | 显示全部楼层

回帖奖励 +2 鱼币

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

使用道具 举报

发表于 2024-8-21 16:07:32 | 显示全部楼层

回帖奖励 +2 鱼币

某一个“天” 发表于 2024-8-21 13:59
气死我了,我也不知道

为什么我这里看不到

评分

参与人数 1荣誉 +3 收起 理由
某一个“天” + 3 坤坤评个分呗~

查看全部评分

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

使用道具 举报

发表于 2024-8-21 16:55:25 | 显示全部楼层

回帖奖励 +2 鱼币

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

使用道具 举报

 楼主| 发表于 2024-8-21 17:12:34 | 显示全部楼层
sfqxx 发表于 2024-8-21 16:07
为什么我这里看不到

现在改了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 17:52:12 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 18:18:12 | 显示全部楼层

回帖奖励 +2 鱼币

你这字体也忒大了吧?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 18:20:52 | 显示全部楼层

回帖奖励 +2 鱼币

OIer 理想的计算器其实一个命令行 Python 就足矣。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 18:27:45 | 显示全部楼层

回帖奖励 +2 鱼币

不对劲,完整代码你是不是动手脚了

好大~
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 20:57:18 | 显示全部楼层

回帖奖励 +2 鱼币

啊,我的标题这么快就火了(不是)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-3 01:18

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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