某一个“天” 发表于 2024-8-21 12:55:04

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

创作背景

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

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






往期版本

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

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


注意事项

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


代码思路

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

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

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

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

球评分~{:10_256:}

"""
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 =
      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 = )]
                  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 =
                            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 = 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()
@isdkz @ba21 @KeyError @zhangjinxuan @sfqxx @不二如是 @python爱好者. @小甲鱼的三师弟 @sfqxx_小 @柿子饼同学 @陈尚涵
大家帮忙@一点人

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

某一个“天” 发表于 2024-8-21 12:59:02

@不二如是 好奇怪,我几乎整个帖子都是你个人资料的链接{:10_266:}

FishC 发表于 2024-8-21 12:59:07

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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

liuhongrun2022 发表于 2024-8-21 13:22:54

你怎么搞的代码里全是不二的链接

另外代码好像没给全

歌者文明清理员 发表于 2024-8-21 13:53:57

while True: print(round(eval(input()), 15))

三体人的智子 发表于 2024-8-21 13:56:11

@不二如是 为什么全是你的个人资料{:10_291:}

某一个“天” 发表于 2024-8-21 13:59:08

liuhongrun2022 发表于 2024-8-21 13:22
你怎么搞的代码里全是不二的链接

另外代码好像没给全

气死我了,我也不知道

18408238295 发表于 2024-8-21 14:04:49

我记得小鱼里面说的用decimal可以精确计算0.1+0.2

不二如是 发表于 2024-8-21 15:08:41

{:10_256:}{:10_256:}{:10_256:}学习

tommyyu 发表于 2024-8-21 15:21:08

import os
os.system('calc')

sfqxx 发表于 2024-8-21 16:01:42

tommyyu 发表于 2024-8-21 15:21


{:10_256:}

sfqxx 发表于 2024-8-21 16:07:32

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

为什么我这里看不到{:10_257:}

很cool的阳 发表于 2024-8-21 16:55:25

{:7_113:}

某一个“天” 发表于 2024-8-21 17:12:34

sfqxx 发表于 2024-8-21 16:07
为什么我这里看不到

现在改了

sfqxx 发表于 2024-8-21 17:52:12

某一个“天” 发表于 2024-8-21 17:12
现在改了

收到

小甲鱼的二师兄 发表于 2024-8-21 18:18:12

你这字体也忒大了吧?

zhangjinxuan 发表于 2024-8-21 18:20:52

OIer 理想的计算器其实一个命令行 Python 就足矣。

三体人的智子 发表于 2024-8-21 18:27:45

不对劲,完整代码你是不是动手脚了{:10_256:}

好大~

zhangchenyvn 发表于 2024-8-21 20:57:18

啊,我的标题这么快就火了(不是)
页: [1] 2
查看完整版本: 0.1+0.2可以等于0.3!全FishC最好的计算器(不是),满足你对计算器的一切幻想