计算器是我们日常生活中都会用到的一个应用程序。本节教程中,我们利用Python自带的图形用户界面库Tkinter,构建一个Python计算器程序。
Tkinter作为Python的标准GUI(图形用户界面)库,是Python中设计图形界面最常用的一个标准库,简单易用,不需要额外安装。此外,Tkinter是跨平台的,因此相同的代码可以在macOS,Windows和Linux上运行。
计算器程序效果如下图所示:
以下是计算器程序完整的示例代码:
动手练一练:
import tkinter as tk
# 定义计算器Calculator类
class Calculator:
# 初始化界面控件
def __init__(self, master):
self.master = master
self.master.title("简易计算器")
# 设置窗口不可通过鼠标拉伸
self.master.resizable(0, 0)
# 设置主窗口的初始大小
self.master.geometry('385x400')
# 用于显示计算结果的可变文本
self.result = tk.StringVar()
# 用于显示计算方程
self.equation = tk.StringVar()
# 设置默认值
self.result.set(' ')
self.equation.set('0')
# 创建一个包含两个Label的Frame,当作计算器的显示框
frame = tk.Frame(self.master, borderwidth=2, relief="groove")
frame.grid(row=0, column=0, columnspan=5, padx=10, pady=10)
self.lb = tk.Label(frame, textvariable=self.equation, bg="white", font=("黑体", 28), anchor=tk.SE, width=19, height=1)
self.lb.grid(row=0, column=0, columnspan=5)
self.lb1 = tk.Label(frame, textvariable=self.result, bg="white", font=("黑体", 28), anchor=tk.SE, width=19, height=1)
self.lb1.grid(row=1, column=0, columnspan=5)
# 创建计算器按钮
self.bu_clear = tk.Button(self.master, text="C", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.clear())
self.bu_clear.grid(padx=5,pady=5, row=2,column=0)
self.bu_back = tk.Button(self.master, text="←", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.back())
self.bu_back.grid(padx=5, pady=5,row=2,column=1)
self.bu_chu = tk.Button(self.master, text="/", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("/"))
self.bu_chu.grid(padx=5, pady=5, row=2, column=2)
self.bu_cal = tk.Button(self.master, text="*", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("*"))
self.bu_cal.grid(padx=5, pady=5, row=2, column=3)
self.bu_7 = tk.Button(self.master, text="7", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("7"))
self.bu_7.grid(padx=5,pady=5,row=3,column=0)
self.bu_8 = tk.Button(self.master, text="8", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("8"))
self.bu_8.grid(padx=5,pady=5,row=3,column=1)
self.bu_9 = tk.Button(self.master, text="9", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("9"))
self.bu_9.grid(padx=5,pady=5,row=3,column=2)
self.bu_sub = tk.Button(self.master, text="-", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("-"))
self.bu_sub.grid(padx=5, pady=5, row=3, column=3)
self.bu_4 = tk.Button(self.master, text="4", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("4"))
self.bu_4.grid(padx=5,pady=5,row=4,column=0)
self.bu_5 = tk.Button(self.master, text="5", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("5"))
self.bu_5.grid(padx=5,pady=5,row=4,column=1)
self.bu_6 = tk.Button(self.master, text="6", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("6"))
self.bu_6.grid(padx=5,pady=5,row=4,column=2)
self.bu_add = tk.Button(self.master, text="+", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("+"))
self.bu_add.grid(padx=5, pady=5, row=4, column=3)
self.bu_1 = tk.Button(self.master, text="1", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("1"))
self.bu_1.grid(padx=5,pady=5,row=5,column=0)
self.bu_2 = tk.Button(self.master, text="2", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("2"))
self.bu_2.grid(padx=5,pady=5,row=5,column=1)
self.bu_3 = tk.Button(self.master, text="3", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("3"))
self.bu_3.grid(padx=5,pady=5,row=5,column=2)
self.bu_equal = tk.Button(self.master, text="=", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.equal())
self.bu_equal.grid(padx=5,pady=5, row=5,column=3)
self.bu_0 = tk.Button(self.master, text="0", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("0"))
self.bu_0.grid(padx=5,pady=5,row=6,column=0)
self.bu_sum = tk.Button(self.master, text=".", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation("."))
self.bu_sum.grid(padx=5, pady=5, row=6,column=1)
self.bu_l_bracket = tk.Button(self.master, text="(", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation("("))
self.bu_l_bracket.grid(padx=5, pady=5, row=6,column=2)
self.bu_r_bracket = tk.Button(self.master, text=")", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation(")"))
self.bu_r_bracket.grid(padx=5, pady=5, row=6,column=3)
# 返回函数
def back(self):
temp_equ = self.equation.get()
# 每一次只删除一个
self.equation.set(temp_equ[:-1])
# 清零函数
def clear(self):
self.equation.set('0')
self.result.set(' ')
# 计算器符号获取
def calculation(self, arg):
temp_equ = self.equation.get()
temp_result = self.result.get()
# 计算器输入前还没有结果,则设置计算结果为空
if temp_result != ' ':
self.result.set(' ')
# 如果输入第一个数字为0,则紧跟后面不能是数字,只能是小数点或运算符
if temp_equ == '0' and (arg not in ['.', '+', '-', '*', '÷']):
temp_equ = ''
# 运算符后面也不能出现0和数字的组合,比如02和08
if len(temp_equ) > 2 and temp_equ[-1] == '0':
if (temp_equ[-2] in ['+', '-', '*', '÷']) and (
arg in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(']):
temp_equ = temp_equ[:-1]
temp_equ = temp_equ + arg
self.equation.set(temp_equ)
# 执行计算函数
def equal(self):
temp_equ = self.equation.get()
temp_equ = temp_equ.replace('÷', '/')
if temp_equ[0] in ['+', '-', '*', '÷']:
temp_equ = '0' + temp_equ
print(temp_equ)
try:
# 保留两位小数
answer = '%.2f' % eval(temp_equ)
self.result.set(str(answer))
# 捕获异常,包括除零错误或语法错误,返回“输入错误”
except (ZeroDivisionError, SyntaxError):
self.result.set(str('输入错误'))
# 当前模块直接被执行
if __name__ == "__main__":
app = tk.Tk()
my_cal = Calculator(app)
# 开启主循环,让窗口处于显示状态
app.mainloop()
计算器程序代码解析
1、界面布局
首先,通过“import tkinter as tk”导入tkinter模块,再使用class关键字定义了一个计算器Calculator类。在Calculator类中,通过构造方法“_init_()”初始化界面控件。代码如下:
import tkinter as tk
# 定义计算器Calculator类
class Calculator:
# 初始化界面控件
def __init__(self, master):
self.master = master
self.master.title("简易计算器")
# 设置窗口不可通过鼠标拉伸
self.master.resizable(0, 0)
# 设置主窗口的初始大小
self.master.geometry('385x400')
# 用于显示计算结果的可变文本
self.result = tk.StringVar()
# 用于显示计算方程
self.equation = tk.StringVar()
# 设置默认值
self.result.set(' ')
self.equation.set('0')
# 创建一个包含两个Label的Frame,当作计算器的显示框
frame = tk.Frame(self.master, borderwidth=2, relief="groove")
frame.grid(row=0, column=0, columnspan=5, padx=10, pady=10)
self.lb = tk.Label(frame, textvariable=self.equation, bg="white", font=("黑体", 28), anchor=tk.SE, width=19, height=1)
self.lb.grid(row=0, column=0, columnspan=5)
self.lb1 = tk.Label(frame, textvariable=self.result, bg="white", font=("黑体", 28), anchor=tk.SE, width=19, height=1)
self.lb1.grid(row=1, column=0, columnspan=5)
# 创建计算器按钮
self.bu_clear = tk.Button(self.master, text="C", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.clear())
self.bu_clear.grid(padx=5,pady=5, row=2,column=0)
self.bu_back = tk.Button(self.master, text="←", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.back())
self.bu_back.grid(padx=5, pady=5,row=2,column=1)
self.bu_chu = tk.Button(self.master, text="/", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("/"))
self.bu_chu.grid(padx=5, pady=5, row=2, column=2)
self.bu_cal = tk.Button(self.master, text="*", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("*"))
self.bu_cal.grid(padx=5, pady=5, row=2, column=3)
self.bu_7 = tk.Button(self.master, text="7", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("7"))
self.bu_7.grid(padx=5,pady=5,row=3,column=0)
self.bu_8 = tk.Button(self.master, text="8", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("8"))
self.bu_8.grid(padx=5,pady=5,row=3,column=1)
self.bu_9 = tk.Button(self.master, text="9", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("9"))
self.bu_9.grid(padx=5,pady=5,row=3,column=2)
self.bu_sub = tk.Button(self.master, text="-", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("-"))
self.bu_sub.grid(padx=5, pady=5, row=3, column=3)
self.bu_4 = tk.Button(self.master, text="4", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("4"))
self.bu_4.grid(padx=5,pady=5,row=4,column=0)
self.bu_5 = tk.Button(self.master, text="5", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("5"))
self.bu_5.grid(padx=5,pady=5,row=4,column=1)
self.bu_6 = tk.Button(self.master, text="6", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("6"))
self.bu_6.grid(padx=5,pady=5,row=4,column=2)
self.bu_add = tk.Button(self.master, text="+", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("+"))
self.bu_add.grid(padx=5, pady=5, row=4, column=3)
self.bu_1 = tk.Button(self.master, text="1", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("1"))
self.bu_1.grid(padx=5,pady=5,row=5,column=0)
self.bu_2 = tk.Button(self.master, text="2", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("2"))
self.bu_2.grid(padx=5,pady=5,row=5,column=1)
self.bu_3 = tk.Button(self.master, text="3", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("3"))
self.bu_3.grid(padx=5,pady=5,row=5,column=2)
self.bu_equal = tk.Button(self.master, text="=", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.equal())
self.bu_equal.grid(padx=5,pady=5, row=5,column=3)
self.bu_0 = tk.Button(self.master, text="0", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, command=lambda: self.calculation("0"))
self.bu_0.grid(padx=5,pady=5,row=6,column=0)
self.bu_sum = tk.Button(self.master, text=".", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation("."))
self.bu_sum.grid(padx=5, pady=5, row=6,column=1)
self.bu_l_bracket = tk.Button(self.master, text="(", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation("("))
self.bu_l_bracket.grid(padx=5, pady=5, row=6,column=2)
self.bu_r_bracket = tk.Button(self.master, text=")", bg="#b4b2b2", font=("黑体", 20), width=5, height=1, justify=tk.LEFT,command=lambda: self.calculation(")"))
self.bu_r_bracket.grid(padx=5, pady=5, row=6,column=3)
2、点击按钮时触发回调函数
通过Button控件中的command参数来执行按钮关联的回调函数。当按钮被点击时,会执行lambda函数。lambda匿名函数可以传参数给回调函数,例如“command=lambda: self.calculation("8")”,这里传的参数是字符串:“8”。计算器上的每一个按钮包含的文本值不同,所以对应的参数各不相同。
3、Calculator类中定义的函数
back()函数对应计算器上面的“回退”按钮,通过back()函数获取计算器符号,clear()函数对应计算器上面的“清除”按钮,最后通过equal()函数执行计算。
在equal()函数中,利用eval()函数来执行Python代码字符串表达式。这个过程必须限制不合理的输入表达式,那么如何判断用户输入的表达式是否合理?我们可以在程序执行前设置“try...except”语句来捕获并处理用户的异常输入,如果“except”有捕获到异常则输出字符串“输入错误”。代码如下:
# 返回函数
def back(self):
temp_equ = self.equation.get()
# 每一次只删除一个
self.equation.set(temp_equ[:-1])
# 清零函数
def clear(self):
self.equation.set('0')
self.result.set(' ')
# 计算器符号获取
def calculation(self, arg):
temp_equ = self.equation.get()
temp_result = self.result.get()
# 计算器输入前还没有结果,则设置计算结果为空
if temp_result != ' ':
self.result.set(' ')
# 如果输入第一个数字为0,则紧跟后面不能是数字,只能是小数点或运算符
if temp_equ == '0' and (arg not in ['.', '+', '-', '*', '÷']):
temp_equ = ''
# 运算符后面也不能出现0和数字的组合,比如02和08
if len(temp_equ) > 2 and temp_equ[-1] == '0':
if (temp_equ[-2] in ['+', '-', '*', '÷']) and (
arg in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(']):
temp_equ = temp_equ[:-1]
temp_equ = temp_equ + arg
self.equation.set(temp_equ)
# 执行计算函数
def equal(self):
temp_equ = self.equation.get()
temp_equ = temp_equ.replace('÷', '/')
if temp_equ[0] in ['+', '-', '*', '÷']:
temp_equ = '0' + temp_equ
print(temp_equ)
try:
# 保留两位小数
answer = '%.2f' % eval(temp_equ)
self.result.set(str(answer))
# 捕获异常,包括除零错误或语法错误,返回“输入错误”
except (ZeroDivisionError, SyntaxError):
self.result.set(str('输入错误'))