tkinter模块是Python标准的TK GUI工具包接口,可以实现一些较为简单GUI的创建。
可以通过点击桌面快捷方式直接运行,无须人为打开Python。
修改代码保存后,程序也会发生相应的改变。
import tkinter as tk
import tkinter.messagebox as mes
注:
要想使用tkinter的弹窗组件,必须导入tkinter.messagebox
def operation(num):
content = buf_bottom.get()
# 使用变量对象buf_bottom的get方法,获取标签内的文字信息
buf_bottom.set(content+num)
def clear():
buf_top.set('')
# 使用变量对象的set方法将标签内容设置为空字符串
buf_bottom.set('')
显示框分上下两部分,之所以这样分,是希望实现这样的一个效果。
上面的标签对象用于展示计算过程中使用的表达式,下面的标签则是展示未完成的表达式以及计算结果的展示。
这里我们使用eval实现计算结果的获取,eval()是Python的内建函数,它接受一个字符串,将该字符串作为Python代码运行后,返回结果。
def calculate():
content = buf_bottom.get()
buf_top.set(content + ' = ')
try:
buf_bottom.set(eval(content))
# 将except ZeroDivisionError放在except的前面可以保证except ZeroDivisionError的正常执行
# except 包含 except ZeroDivisionError
except ZeroDivisionError:
# 处理除数为零的异常情况
buf_bottom.set('Infiniti')
# 弹出警示窗口
mes.showwarning('注意', '请不要使用零作为除数')
except:
# 处理所有的异常情况
# 弹出错误提示窗口
mes.showerror('错误', '输入的表达式有误,请重新输入')
在异常处理时要注意顺序,否则可能有些操作永远也执行不了。
if __name__ == '__main__':
# 保证下方代码在本文件作为模块导入其他文件时不会执行
# 创建主窗口
calc = tk.Tk()
# 指定程序的宽高
WIDTH_R = 283
HEIGHT_R = 335
# 获取计算机屏幕的宽高
WIDTH_W = calc.winfo_screenwidth()
HEIGHT_W = calc.winfo_screenheight()
# 设置应用名称
calc.title('计算器')
# 设置应用图标(仅指定ico文件才有效,png等图片无法正常显示)
calc.iconbitmap('./calculation.ico')
# 设置主窗口背景颜色
calc['background'] = '#d9d6c3'
# 将程序移动到屏幕中央
calc.geometry(f'{WIDTH_R}x{HEIGHT_R}+{(WIDTH_W - WIDTH_R) // 2}+{(HEIGHT_W - HEIGHT_R) // 2}')
注:
calc.geometry(f’{WIDTH_R}x{HEIGHT_R}+{(WIDTH_W - WIDTH_R) // 2}+{(HEIGHT_W - HEIGHT_R) // 2}')
(WIDTH_W - WIDTH_R) // 2 --> WIDTH_W // 2 - WIDTH_R // 2
(HEIGHT_W - HEIGHT_R) // 2 --> HEIGHT_W // 2 - HEIGHT_R // 2
程序中使用的图标在这个链接里:
https://s1.chu0.com/src/img/png/bf/bfc39031c057479aad0e94706d4d26bb.png?imageMogr2/auto-orient/thumbnail/!132x132r/gravity/Center/crop/132x132/quality/85/&e=1735488000&token=1srnZGLKZ0Aqlz6dk7yF4SkiYf4eP-YrEOdM1sob:q3YCeYP0-2kOdXQG7LDXmls337w=
# 布局表达式展示区域
# 创建变量对象,便于后续获取或更改变量的值
buf_top = tk.StringVar()
# 如果需要让标签对象的显示内容由一个字符串变量来实现,Label的参数就不能用text,需要使用textvariable
buffer = tk.Label(calc, textvariable=buf_top, bg='#6f6d85', fg='#d3d7d4', height=1, width=10,
font=('arial', 14, 'normal'), anchor='se', pady=3, padx=2)
# sticky参数可以实现类似pack方法的fill参数, 使标签横向铺满
buffer.grid(sticky=tk.W + tk.E, row=0, column=0, columnspan=4)
buf_bottom = tk.StringVar()
buffer = tk.Label(calc, textvariable=buf_bottom, bg='#6f6d85', fg='#fff', height=1, width=10,
font=('arial', 18, 'normal'), anchor='se', pady=3, padx=2)
buffer.grid(sticky=tk.W + tk.E, row=1, column=0, columnspan=4)
标签的位置,由参数anchor的属性值决定
上述图片引用自C语言中文网
标签的位置默认是居中的。
参数值及其代表的方位可能不太好记忆,但只要记住了东西南北四个方位,记忆起来就方便多了。
方位 | 英文表示 |
---|---|
东 | East |
西 | West |
南 | South |
北 | North |
# C
tk.Button(calc, text='C', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: clear()).grid(row=2, column=0, padx=5, pady=5)
# 0
tk.Button(calc, text=0, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('0')).grid(row=5, column=1, padx=5, pady=5)
# 1
tk.Button(calc, text=1, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('1')).grid(row=2, column=1, padx=5, pady=5)
# 2
tk.Button(calc, text=2, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('2')).grid(row=2, column=2, padx=5, pady=5)
# 3
tk.Button(calc, text=3, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('3')).grid(row=3, column=0, padx=5, pady=5)
# 4
tk.Button(calc, text=4, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('4')).grid(row=3, column=1, padx=5, pady=5)
# 5
tk.Button(calc, text=5, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('5')).grid(row=3, column=2, padx=5, pady=5)
# 6
tk.Button(calc, text=6, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('6')).grid(row=4, column=0, padx=5, pady=5)
# 7
tk.Button(calc, text=7, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('7')).grid(row=4, column=1, padx=5, pady=5)
# 8
tk.Button(calc, text=8, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('8')).grid(row=4, column=2, padx=5, pady=5)
# 9
tk.Button(calc, text=9, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('9')).grid(row=5, column=0, padx=5, pady=5)
# 加号
tk.Button(calc, text='+', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('+')).grid(row=2, column=3, padx=5, pady=5)
# 乘号
tk.Button(calc, text='*', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('*')).grid(row=4, column=3, padx=5, pady=5)
# 除号
tk.Button(calc, text='/', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('/')).grid(row=3, column=3, padx=5, pady=5)
# 等号
tk.Button(calc, text='=', cursor='hand2', width=7, height=1, bg='#f2eada', font='arial 22 normal',
command= calculate).grid(row=5, column=2, columnspan=2, padx=5, pady=5)
# 开启主循环
calc.mainloop()
本想先用循环创建一些按钮,但由于点击按钮后,无法判断点击了哪个按钮。
于是:
# 使用for循环创建0-8的按钮,其余按钮为了布局,得一个一个布置。
face = 0
for row in range(1, 4):
for column in range(3):
tk.Button(calc, text=face, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal', command=lambda: number(face)).grid \
(row=row, column=column, padx=5, pady=5)
face += 1
由于number是一个回调函数,当你点击后才会执行,而此时for循环已经结束(排除你手速足够快的情况),face=9。
因此无论你点哪一个数字按钮,显示的都会是9。
暂时并没有更好的解决方案,如果你知道怎么做,还请不吝赐教。
# 导入模块
import tkinter as tk
import tkinter.messagebox as mes
# 运算公式的拼接与展示
def operation(num):
content = buf_bottom.get()
# 使用变量对象buf_bottom的get方法,获取标签内的文字信息
buf_bottom.set(content+num)
# 将显示框的内容删除
def clear():
buf_top.set('')
buf_bottom.set('')
# 使用eval()函数对表达式求值
def calculate():
content = buf_bottom.get()
buf_top.set(content + ' = ')
try:
buf_bottom.set(eval(content))
# 将except ZeroDivisionError放在except的前面可以保证except ZeroDivisionError的正常执行
# except 包含 except ZeroDivisionError
except ZeroDivisionError:
# 处理除数为零的异常情况
# 弹出警示窗口
buf_bottom.set('Infiniti')
mes.showwarning('注意', '请不要使用零作为除数')
except:
# 处理所有的异常情况
# 弹出错误提示窗口
mes.showerror('错误', '输入的表达式有误,请重新输入')
if __name__ == '__main__':
# 保证下方代码在本文件作为模块导入其他文件时不会执行
# 创建主窗口
calc = tk.Tk()
# 指定程序的宽高
WIDTH_R = 283
HEIGHT_R = 335
# 获取计算机屏幕的宽高
WIDTH_W = calc.winfo_screenwidth()
HEIGHT_W = calc.winfo_screenheight()
# 设置应用名称
calc.title('计算器')
# 设置应用图标(仅指定ico文件才有效,png等图片无法正常显示)
calc.iconbitmap('./calculation.ico')
# 设置主窗口背景颜色
calc['background'] = '#d9d6c3'
# 将程序移动到屏幕中央
calc.geometry(f'{WIDTH_R}x{HEIGHT_R}+{(WIDTH_W - WIDTH_R) // 2}+{(HEIGHT_W - HEIGHT_R) // 2}')
# 布局表达式展示区域
# 创建变量对象,便于后续获取或更改变量的值
buf_top = tk.StringVar()
# 如果需要让标签对象的显示内容由一个字符串变量来实现,Label的参数就不能用text,需要使用textvariable
buffer = tk.Label(calc, textvariable=buf_top, bg='#6f6d85', fg='#d3d7d4', height=1, width=10,
font=('arial', 14, 'normal'), anchor='se', pady=3, padx=2)
# sticky参数可以实现类似pack方法的fill参数, 使标签横向铺满
buffer.grid(sticky=tk.W + tk.E, row=0, column=0, columnspan=4)
buf_bottom = tk.StringVar()
buffer = tk.Label(calc, textvariable=buf_bottom, bg='#6f6d85', fg='#fff', height=1, width=10,
font=('arial', 18, 'normal'), anchor='se', pady=3, padx=2)
buffer.grid(sticky=tk.W + tk.E, row=1, column=0, columnspan=4)
# C
tk.Button(calc, text='C', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: clear()).grid(row=2, column=0, padx=5, pady=5)
# 0
tk.Button(calc, text=0, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('0')).grid(row=5, column=1, padx=5, pady=5)
# 1
tk.Button(calc, text=1, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('1')).grid(row=2, column=1, padx=5, pady=5)
# 2
tk.Button(calc, text=2, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('2')).grid(row=2, column=2, padx=5, pady=5)
# 3
tk.Button(calc, text=3, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('3')).grid(row=3, column=0, padx=5, pady=5)
# 4
tk.Button(calc, text=4, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('4')).grid(row=3, column=1, padx=5, pady=5)
# 5
tk.Button(calc, text=5, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('5')).grid(row=3, column=2, padx=5, pady=5)
# 6
tk.Button(calc, text=6, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('6')).grid(row=4, column=0, padx=5, pady=5)
# 7
tk.Button(calc, text=7, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('7')).grid(row=4, column=1, padx=5, pady=5)
# 8
tk.Button(calc, text=8, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('8')).grid(row=4, column=2, padx=5, pady=5)
# 9
tk.Button(calc, text=9, cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('9')).grid(row=5, column=0, padx=5, pady=5)
# 加号
tk.Button(calc, text='+', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('+')).grid(row=2, column=3, padx=5, pady=5)
# 乘号
tk.Button(calc, text='*', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('*')).grid(row=4, column=3, padx=5, pady=5)
# 除号
tk.Button(calc, text='/', cursor='hand2', width=3, height=1, bg='#f2eada', font='arial 22 normal',
command=lambda: operation('/')).grid(row=3, column=3, padx=5, pady=5)
# 等号
tk.Button(calc, text='=', cursor='hand2', width=7, height=1, bg='#f2eada', font='arial 22 normal',
command= calculate).grid(row=5, column=2, columnspan=2, padx=5, pady=5)
# 开启主循环
calc.mainloop()
创建了一个GUI程序,如果还每次都要在命令行这样打开:
python calculation.py
怕是一种罪孽。
如果想让程序也能像其他桌面应用一样使用,可以这样做:
pythonw calculation.pyw
即可。
此后,即便你重启计算机,也能点击文件直接打卡程序。
相当于你点击.pyw 文件后,系统隐式执行了:
python calculation.py