前言
马上就要实习了,而我却没有拿得出手的项目..哎实力不够啊。还有六个月时间,先从简单开始吧,一步一个脚印,大家一起加油!
“设计很难,模仿不易。”这是我创作计算器时内心的独白。设计出一款产品固然很难,但是你要模仿他设计出类似的一款产品也不容易,你必须要知道它底层实现的逻辑原理。

设计前,天真的我以为,仿造个标准计算器,不就加减乘除平方开根号么这有什么难的?给我一天时间足够啦!确实,实现主干代码并不难,一天确实能完成。但是仅考虑常规计算思路是远远不够的,这样会遗留下诸多bug,如 运算符与开根号求倒数等进行交叉运算后显示结果与预期结果不相符情况等等很多,这也因此让我花了一个多星期的时间才算是让各个运算逻辑相互兼容,尽可能的修复已知BUG。修复BUG过程你必须要假想自己是一个变态老板,就是不按常规思路计算客户的账单,乱点一通。因此,你必须要预判出所有可能出现的情况,我愿称这项目为面向变态老板设计。
前阵子学校附近有疫情,然后学校就急匆匆的上完课就放假了,本想完成全部代码后赶在2021发布博客的,可终究没有实现。家人又叫我去那边帮忙,导致我设计时断时续,很不巧tkinter我也是自学没多久,不够熟练,这次写代码的时候贪快不愿意写备注,想着下次回来看动动脑想下还能加深印象。结果,过几天回来一看哪搭哪都不知道,真的一头雾水,所以又不得不重新找下资料看..这时间就是白白浪费呀,其实你提前备注好也是等价找资料的,所以说,写完代码马上备注很重要。本来连贯的思路经过几天工作的洗礼就没了,你说又要重拾起来,那可得花好一段时间,特别是代码长了之后。所以说我们最好能够完成一件事再干另外一件事。
在设计过程中,我遇到了诸多烦心的地方,如,如何提高代码可读性和使用效率?该先从何入手?是先一个模块一个模块设计还是先规划好所有模块功能再单独拎出来一个一个设计呢?对于刚开始没啥经验的我来说当然是想着走一步算一步,正因如此,我没有考虑整体问题在后面设计过程中导致很多地方出现运算不兼容,显示有误的情况,查错起来那才叫难受,真的是好多时候都想放弃..幸好最后挺过来了,现在回想起来真不容易。还有就是代码,如果可以的话先分析记录一下各个功能实现的逻辑,最好能找出各个功能的共性,然后设计对应的方法,每执行一个功能,就调用那个方法,还有在if条件判断的时候,我们这个计算器有24个按钮,哪些按钮功相似可以放在一起,哪些按钮执行完后就不用再执行下面的语句?考虑好这些情况能让我们提高一定的写代码效率。还有一个就是命名规范,我英语不好,遇到想写又不会的单词就直接百度翻译,目的就是能让大家更好的理解我实现每一步的思路。有时候遇到问题死磕好久找不出来,可以试试找一下你身边的小伙伴,让他来调试一下两下,说不定就能找出问题出现的原因了。
其他也没啥了,我们进入正题吧。
这款计算器部分显示是中文。在这我希望我们国产软件能够越来越好,也为国产标志的软件尽自己一点绵薄之力。
目录
软件介绍
这是一款中文双显计算器,支持主流运算,功能细节上能与win10自带的标准型计算器有百分之60以上的相似度,精度上支持六位小数(可自行修改)。

软件缺陷
1.界面不够美观
2.不能对小数进行开根号
3.不支持键盘输入
4.出现警告框后按钮不会弹起

5. "%", "CE", "清零"三个按钮功能等价 (目前已修复“CE”情况)
提到 "%", "CE" 我真是头疼,百度琢磨了半天也没理解这两个符号表达是什么意思,感觉他们说的win10计算器跟我的win10计算器都不是同一个..因为研究这两个按键花费了不少时间没研究出来,又感觉这也不经常用,我索性就把他们归到清零的功能上了,而我在win10计算器输入数字后点他们确实也是清零了。(CE我会了)
软件设计
1.设计思路
计算器分成两个部分——显示和触控。
1.1显示部分

显示部分分为上显示屏和下显示屏。下显示屏是表示每一步计算的数值,也只显示数值,上显示屏表示的是计算过程。理论上,下屏应为单行显示,可复制,可通过键盘输入数字及运算符(该功能尚未完成),因此,我们选择的控件应为entry,其功能与text相似,而上屏的作用是显示计算过程,里边的元素不可复制,因此上屏选用的控件为label。我们知道,label不能直接更改数据,所以这里引用了可变追踪对象StringVar(),通过改变这个对象的值来改变label显示的值,同样的下层entry控件也需要这个可变对象,因为我们计算操作是使用鼠标点击按钮来实现计算,而不是通过键盘输入数字来计算。
1.2触控部分

这一部分是整个组件的核心。我们需要对按钮绑定事件,以保证每次点击按钮能触发对应的事件。24个按钮里边无非就4种类型 数字(0~9),运算符(加减乘除等于),算法(求倒数求平方开根号相反数)以及回退操作(删除初始化)。在此,我们必须要设定一些变量保存数据,方便我们计算。我设置了四个变量,factor1, factor2, operator, last_click用于记录因子1,因子2,运算符,以及上一次点击。为了简化计算我是直接使用了eval函数和pow函数,如果对这两个函数算法的实现思路感兴趣的朋友可以了解一下我这两篇文章。
记住,在这里你必须要知道每个按钮间都不存在互斥现象,千万不要想当然的以为点了这个按钮之后就不会点击那个按钮,你必须要料想所有可能出现的结果。
1.3思路图解
从开始设计窗口到设计按钮框架大致的思路可以用下面的gif表示

你们看一下这个思路图,有些地方我在下面做出了相应的解释。

解释:
看到“删除”的分支语句,删除一个字符指的是删除下显示屏的一个字符。
看到“加减乘除”的分支语句,重显示的意思就是此时下显示屏显示的值是虚值(即运算结果),当下一次输入数字的时候显示的值会被覆盖掉。
记录前面输入的数字:就是获取此时下显示屏的值。因为运算符不会出现在下显示屏,下显示屏只会记录数字,每出现一次运算符后将会读取一次数据之后下显示屏会处于重显示状态。
直接开平方: 因为我们计算是读取下显示屏的数据,在读取前下方数据如何改变逻辑上都是行得通的。
我以下方gif为例简单讲一下实现过程。

下方显示屏初始值是0, 输入数字后,如果第一个字符是0则需要将其覆盖,覆盖后下方显示为3。点击乘号后,因子factor1记录下方显示屏的值(3),运算符operator记录此时点击的运算符(*)。上方显示屏显示 因子1和运算符,下方显示屏处于重显示状态。当再次输入数字5的时候,5覆盖掉3的值,下方显示屏显示5,点击运算符+号后,因为因子1存在了,5的值赋值给因子2。然后就使用eval函数对“因子1 运算符 因子2”这个表达式进行求解,将的出来的结果(15)赋值给因子1,上方显示屏继续显示 因子1和运算符,下方显示屏再回到重显示状态。点击6,下方显示为6,再点击等号。用因子2记录下方显示屏的值6,然后再用eval对“因子1 运算符 因子2”表达式进行求解,求解后上方显示计算过程,下方继续处于重显示状态。
看到这里细心的朋友会发现我前面说这些按钮只有四种类型,但是在上方的思路图中却出现了不止四条的分支,也就是出现了不止四种情况,这是为什么呢?我只能说个人习惯吧,一开始设计的时候我就把他们分开了,所以现在写的时候也这么写了,但是存在个别按钮(等号=),不分开我也要将它分开,或许我将它搞得太特别了。至于为什么,在详细步骤那里我再好好跟大伙说说原因。
其实,上方思路图只展示了常规使用计算器的思路,而只考虑上方几种情况是远远不够的,为保证计算器稳定性我们必须考虑更多情形,即,非常规情况。
2.详细步骤
2.1创建窗口对象
首先定义类TkWindows,之后导入tkinter包,在类的init方法里边创建窗口对象,以及设定好尺寸,名称等参数。尺寸的话我根据win10计算器设计的,虽然还是有差别,凑合用吧,设置窗体尺寸和按钮框架显示框架的尺寸我也花了不少时间。设置完尺寸后要设置最大拉伸长度,因为拉伸后那些按钮和框架不会跟着拉伸,还有就是设定窗口名了。

代码如下:
import tkinter
class TkWindows:
def __init__(self):
# 创建窗口对象
self.win = tkinter.Tk()
# 设置窗口宽度,高度以及窗口初始位置 x 为小写字母x 第一个加号后面参数是x轴坐标,第二个参数是y轴坐标
self.win.geometry("360x460+570+200")
# 定义拉伸的最大尺寸
self.win.maxsize(width=360, height=460)
# 定义窗口名称
self.win.title("李帅哥的标准型计算器")
在设计思路部分我已经大概提过有哪些变量,哪些控件了,因此先提前在init里边创建好。
# 初始化数据
self.lower_display = None # 上显示屏
self.upper_display = None # 下显示屏
self.entry = None
self.label = None
self.operator = "" # 运算符
self.factor1 = ""
self.factor2 = ""
self.last_click = "" # 上一次点击
然后进入消息循环
# 进入消息循环
self.win = tkinter.mainloop()
在主函数调用该类
if __name__ == '__main__':
TkWindows()
点击运行,就能出现框体了

2.2创建显示框架
定义方法text_frame,创建一个frame框架text_frame,将该框架放置到win窗口中的上部分。
# 显示屏——双显
def text_frame(self):
text_frame = tkinter.Frame(self.win, width=360, height=190)
text_frame.pack(side="top")
frame 第一个参数为要放置的对象,第二个参数是宽度,应与窗口宽度一致,第三个参数是高度。
然后将该方法添加到init里面,就能生成这个框架了。
self.button_frame()
2.3放置显示屏
上显示屏使用的控件是label,下显示屏使用的控件是entry。它们都有一个参数叫textvariable,是用来接收可变对象,说白了就是跟可变对象绑定后,可变对象的值发生改变,显示框的值也发生改变。常见能接收的类型有StringVar() 和 IntVar()。因为我们计算是使用eval函数,里边的表达式是字符串类型的,所以我们的接收类型就使用了StringVar(),其常用的方法有get方法--获取当前显示框的文本,和set方法--设置显示框的值。之后我们会大量使用这两个方法,是不是很简单粗暴?因此在text_frame方法里面添加如下语句。
# 定义上下层显示屏可变追踪对象用于及时更新数据
self.lower_display = tkinter.StringVar()
self.upper_display = tkinter.StringVar()
# 设定下层显示的初始值
self.lower_display.set("0")
添加完后我们下显示屏默认会显示0,而上显示屏默认显示。
创建上显示屏label
# 设定上层显示组件, label——可多行显示,不可复制,不可直接通过键盘更改文本内容
self.label = tkinter.Label(text_frame, font=("loMa", 14),
textvariable=self.upper_display, bd=0, anchor="se", bg="LightGray")
- text_frame: label要放置的对象。我们要把label放置在text_frame框架中。
- font:字体。里边第一个参数是字体样式,第二个参数是字体大小。
- textvariable:绑定可变对象。这里我们绑定的是上显示屏,其类型是StringVar()。
- bd:边框大小。因为我们上下显示屏要看成一个整体,所以不能有边框,这里设置为0。
- anchor:图形放置的位置。"se"表示东南部。相当于放在右下角了。说到这东西我必须吐槽一下,label明明也有justify属性(对齐方式),我把它修改为向右对齐却一点用都没有还是会居中显示,而entry修改这个属性后又能向右对齐,这给我整无语了。
- bg:背景色。我为什么用这个颜色呢,因为我win10计算器是在pycharm下打开的,刚好那时候就显示这个色,我就把计算器调成这个颜色了,结果win10计算器颜色会变..想改其他颜色可以参

本文记录了一位编程新手从零开始制作计算器应用的过程,包括设计思路、详细步骤和遇到的挑战。作者通过实现加减乘除、开根号、求平方等功能,探讨了如何处理各种运算逻辑,以及如何处理界面布局和按钮事件。在开发过程中,作者意识到代码可读性、错误处理和代码维护的重要性,并分享了在开发过程中学到的经验和教训。
https://blog.csdn.net/lishuaigell/article/details/122474662
最低0.47元/天 解锁文章
2632

被折叠的 条评论
为什么被折叠?



