Python制作简易计算器(GUI)---Tkinter

Tkinter简介

tkinter模块是Python标准的TK GUI工具包接口,可以实现一些较为简单GUI的创建。

Tkinter 与 PyQt5 的比较

Tkinter

  1. 麻雀虽小,五脏俱全
  2. TK工具集使用TCL(Tool Command Language)语言开发
  3. 运行相同的程序时,运行速度快于pyqt5
  4. 组件能满足基本使用
  5. 程序界面较简陋
  6. 开发时,使用的语句更短更易懂
  7. Python内置的标准库

PyQt5

  1. Qt框架使用C++开发
  2. 组件丰富
  3. 运行相同的程序时,运行速度慢与tkinter
  4. 使用Qt designer可以在不使用代码的情况下创建一个程序
  5. 界面的观赏性更强
  6. 调试难度更大

项目展示

计算器
可以通过点击桌面快捷方式直接运行,无须人为打开Python。
修改代码保存后,程序也会发生相应的改变。
快捷方式

导入模块

import tkinter as tk
import tkinter.messagebox as mes

注:
要想使用tkinter的弹窗组件,必须导入tkinter.messagebox

函数封装

1. 运算公式的拼接与展示

def operation(num):
    content = buf_bottom.get()
    # 使用变量对象buf_bottom的get方法,获取标签内的文字信息
    buf_bottom.set(content+num)

2. 将显示框的内容删除

def clear():
    buf_top.set('')
   	# 使用变量对象的set方法将标签内容设置为空字符串
    buf_bottom.set('')

显示框分上下两部分,之所以这样分,是希望实现这样的一个效果。
分行原因
上面的标签对象用于展示计算过程中使用的表达式,下面的标签则是展示未完成的表达式以及计算结果的展示。

3. 使用eval()函数对表达式求值

这里我们使用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('错误', '输入的表达式有误,请重新输入')

在异常处理时要注意顺序,否则可能有些操作永远也执行不了。

主逻辑

1. 布局窗口

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}')

  1. geometry方法接受一个字符串参数,依据它设置程序的宽高以及左上角的xy坐标。
    宽高之间必须 小写的字母x连接 ,其他数据之间则用 + 号连接。
  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=

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)

标签的位置,由参数anchor的属性值决定

anchor参数值及其代表的具体位置


上述图片引用自C语言中文网

标签的位置默认是居中的。
参数值及其代表的方位可能不太好记忆,但只要记住了东西南北四个方位,记忆起来就方便多了。

方位英文表示
East
西West
South
North

3. 布局按钮

   # 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()

实现桌面点击直接启动计算器(无须人为开启Python)

创建了一个GUI程序,如果还每次都要在命令行这样打开:

python calculation.py

怕是一种罪孽。
如果想让程序也能像其他桌面应用一样使用,可以这样做:

  1. 将文件的后缀名由 .py 改为 .pyw
  2. 在命令行中输入:

pythonw calculation.pyw

即可。
此后,即便你重启计算机,也能点击文件直接打卡程序。
相当于你点击.pyw 文件后,系统隐式执行了:

python calculation.py

  • 29
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinaryMoon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值