python语言利用Tkinter实现GUI计算器
python语言利用Tkinter实现GUI计算器|(一)计算器基本功能设计
python语言利用Tkinter实现GUI计算器|(二)优化计算器
python语言利用Tkinter实现GUI计算器|(三)pyinstaller打包:带图标计算器
Calculator计算器的优化问题
在上一篇博客:Python语言利用tkinter库实现用户界面计算器的过程中,有如下几个方面待优化,可使Calculator更健壮。
1.关于用户乱输入,使软件奔溃的问题。
本计算器计算功能是通过获取将输入表达式,利用eval()函数来执行python代码字符串的。那么就要杜绝不合理的输入表达式,如何过滤掉用户不合理的输入,需要在程序执行前设置try...except...else...finally
语句,来捕捉用户的异常输入,设置异常输入响应为Error。Calculator类中,执行run函数修改如下:
2.优化冗于代码
优化方向:
- 初始化布局页面代码冗余;
- lambda匿名函数包裹回调函数时传参的问题
代码实现:这里主要优化初始化函数,其他函数采用继承。
优化计算器类Calc继承Calculator的back,clear,run,getNum。增加initPage来定义页面控件布局。
# 计算器,优化程序
class Calc(Calculator):
def __init__(self, master):
self.master = master
self.master.title("Calculator")
self.master.resizable(0, 0) # 设置窗口不可拉伸
self.master.geometry('320x420') # 设置主窗口的初始尺寸
self.result = StringVar() # 用于显示结果的可变文本
self.equation = StringVar() # 显示计算方程
self.result.set(' ')
self.equation.set('0')
self.labels = ['<-', '(', ')', '÷',
'7', '8', '9', '*',
'4', '5', '6', '-',
'1', '2', '3', '+',
'MC', '0', '.', '=',
]
# 显示框
self.show_result_eq = Label(self.master, bg='white', fg='black',
font=('Arail', '16'), bd='0',
textvariable=self.equation, anchor='se')
self.show_result = Label(self.master, bg='white', fg='black',
font=('Arail', '20'), bd='0',
textvariable=self.result, anchor='se')
# 按钮
# self.button_dict = {}
# Layout布局
self.show_result_eq.place(x='10', y='10', width='300', height='50')
self.show_result.place(x='10', y='60', width='300', height='50')
self.initPage()
def initPage(self):
X = ['10', '90', '170', '250']
Y = ['150', '205', '260', '315', '370']
lengths = len(self.labels) # 20
y_ = -1
# 设置按钮并布局
for label in self.labels:
print(label)
index = self.labels.index(label)
x_ = index % 4
if x_ == 0:
y_ += 1
if label == '<-':
button = Button(self.master, text=label, bg='DarkGray', command=self.back)
button.place(x=X[x_], y=Y[y_], width='60', height='40')
elif label == '=':
button = Button(self.master, text=label, bg='DarkGray', command=self.run)
button.place(x=X[x_], y=Y[y_], width='60', height='40')
elif label == 'MC':
button = Button(self.master, text=label, bg='DarkGray', command=self.clear)
button.place(x=X[x_], y=Y[y_], width='60', height='40')
else:
# 因为lambda函数有传参功能,但只有调用的时候才传参,所以数字按钮永远会调用最后一个label值。解决方案是自己洗一个button来保存label值
button = NumButton(self.master, text=label, bg='DarkGray', fun=self.getNum)
button.btn.place(x=X[x_], y=Y[y_], width='60', height='40')
# self.button_dict[label] = button
重点:以上代码,倒数第二行,我采用自定义的NumButton,而不是原有的Butoon。
因为即使匿名函数lambda函数有传参功能,但只有调用的时候才传参,所以for循环到最后,label变量的值永远为列表最后一个=
等于符号,一度让人无解,只能自定义一个按钮类型NumButton
,来保存中间值。使按钮们都有自己的文本值,并且command回调的时候能够准确传参。
class NumButton():
def __init__(self, frame, text, fun, **kwargs):
# side = kwargs.get('side') if 'side' in kwargs else () # 此处没用上
self.btn = Button(
frame,
text=text,
activeforeground="blue",
activebackground="pink",
bg='DarkGray',
command=lambda: fun(text)
)
注意
形式参数frame, text, fun
frame是根部件。
text按钮的标签文本,
fun函数对象,就是待回调的函数。
3.测试计算器
if __name__ == "__main__":
root = Tk()
# my_cal = Calculator(root)
my_cal = Calc(root)
root.mainloop()
自定义的NumButton设置了按钮激活时背景和字体的颜色变化,所以有点颜色。Button自己也可以设置的。
正常工作!!