鱼C论坛

 找回密码
 立即注册
查看: 354|回复: 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)


球评分~
"""
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()
@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有你更精彩^_^

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-21 12:59:02 | 显示全部楼层
@不二如是 好奇怪,我几乎整个帖子都是你个人资料的链接
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

另外代码好像没给全
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

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

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

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

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

另外代码好像没给全

气死我了,我也不知道
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

我记得小鱼里面说的用decimal可以精确计算0.1+0.2
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

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

回帖奖励 +2 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

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

为什么我这里看不到

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

现在改了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-21 17:52:12 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

你这字体也忒大了吧?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

OIer 理想的计算器其实一个命令行 Python 就足矣。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

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

好大~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +2 鱼币

啊,我的标题这么快就火了(不是)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-17 03:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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