本次任务主旨在于对Tkinter进行UI编程练习,不关注计算器的算法细节。
所以计算器实现是直接将输入的表达式用eval()函数传入编译,得到答案。
具体实现过程:
#创建窗口
创建一个340x720固定大小,标题为”计算器“的窗口
from tkinter import *
root = Tk() #创造窗口
root.title("计算器") #更改标题
root.resizable(0,0) #窗口大小不可更改
root.geometry("340x720") #窗口大小
mainloop()
#增加按键
接下来把设计好的Button添加进去
我设计了18个Button,10个数字,4个运算符号(+,-,*,/),1个小数点,1个等号,1个清屏键和1个删除输入键。
具体来看看Button()函数:
第一个参数是窗口名字,即我们创建的root窗口
之后是text,表示Button上显示的文字
place()中包含Button的位置(以窗口左上角为原点,水平向右x轴,竖直向下y轴)和长宽
每个Button的位置就根据自己设计的界面大小和Button大小计算出即可
from tkinter import *
root = Tk() #创造窗口
root.title("计算器") #更改标题
root.resizable(0,0) #窗口大小不可更改
root.geometry("340x720") #窗口大小
#R0
But_cmp=Button(root,text='=').place(x=100,y=620,width=240,height=100)
But_point=Button(root,text='AC').place(y=620,width=100,height=100)
#R1
But_AC=Button(root,text='.').place(x=0,y=620-1*80,width=80,height=80)
But0=Button(root,text='0').place(x=0+1*80,y=620-1*80,width=80,height=80)
But_back=Button(root,text='<--').place(x=0+2*80,y=620-1*80,width=80,height=80)
But_division=Button(root,text='/').place(x=0+3*80,y=620-1*80,width=100,height=80)
#R2
But1=Button(root,text='1').place(x=0,y=620-2*80,width=80,height=80)
But2=Button(root,text='2').place(x=0+1*80,y=620-2*80,width=80,height=80)
But3=Button(root,text='3').place(x=0+2*80,y=620-2*80,width=80,height=80)
But_multi=Button(root,text='*').place(x=0+3*80,y=620-2*80,width=100,height=80)
#R3
But4=Button(root,text='4').place(x=0,y=620-3*80,width=80,height=80)
But5=Button(root,text='5').place(x=0+1*80,y=620-3*80,width=80,height=80)
But6=Button(root,text='6').place(x=0+2*80,y=620-3*80,width=80,height=80)
But_sub=Button(root,text='-').place(x=0+3*80,y=620-3*80,width=100,height=80)
#R4
But7=Button(root,text='7').place(x=0,y=620-4*80,width=80,height=80)
But8=Button(root,text='8').place(x=0+1*80,y=620-4*80,width=80,height=80)
But9=Button(root,text='9').place(x=0+2*80,y=620-4*80,width=80,height=80)
But_add=Button(root,text='+').place(x=0+3*80,y=620-4*80,width=100,height=80)
mainloop()
#美化Button
接下来可以使用Button()中的参数更改文字大小,背景颜色等等属性
有如下参数可选择
函数 |
描述 |
text |
显示文本内容 |
command |
指定Button的事件处理函数 |
compound |
指定文本与图像的位置关系 |
bitmap |
指定位图 |
focus_set |
设置当前组件得到的焦点 |
master |
代表了父窗口 |
bg |
设置背景颜色 |
fg |
设置前景颜色 |
font |
设置字体大小 |
height |
设置显示高度、如果未设置此项,其大小以适应内容标签 |
relief |
指定外观装饰边界附近的标签,默认是平的,可以设置的参数; flat、groove、raised、ridge、solid、sunken |
width |
设置显示宽度,如果未设置此项,其大小以适应内容标签 |
wraplength |
将此选项设置为所需的数量限制每行的字符,数默认为0 |
state |
设置组件状态;正常(normal),激活(active),禁用(disabled) |
anchor |
设置Button文本在控件上的显示位置 可用值:n(north),s(south),w(west),e(east),和ne,nw,se,sw |
bd |
设置Button的边框大小;bd(bordwidth)缺省为1或2个像素 |
textvariable |
设置Button与textvariable属性 |
from tkinter import *
root = Tk() #创造窗口
root.title("计算器") #更改标题
root.resizable(0,0) #窗口大小不可更改
root.geometry("340x720") #窗口大小
#R0
But_cmp=Button(root,text='=',font = ('微软雅黑',20),bg='orange').place(x=100,y=620,width=240,height=100)
But_point=Button(root,text='AC',font = ('微软雅黑',20),bg='orange').place(y=620,width=100,height=100)
#R1
But_AC=Button(root,text='.',bg='orange',font = ('微软雅黑',15)).place(x=0,y=620-1*80,width=80,height=80)
But0=Button(root,text='0',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-1*80,width=80,height=80)
But_back=Button(root,text='<--',bg='orange',font = ('微软雅黑',15)).place(x=0+2*80,y=620-1*80,width=80,height=80)
But_division=Button(root,text='/',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-1*80,width=100,height=80)
#R2
But1=Button(root,text='1',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-2*80,width=80,height=80) #command后直接跟需要参数的函数会报错
But2=Button(root,text='2',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-2*80,width=80,height=80)
But3=Button(root,text='3',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-2*80,width=80,height=80)
But_multi=Button(root,text='*',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-2*80,width=100,height=80)
#R3
But4=Button(root,text='4',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-3*80,width=80,height=80)
But5=Button(root,text='5',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-3*80,width=80,height=80)
But6=Button(root,text='6',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-3*80,width=80,height=80)
But_sub=Button(root,text='-',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-3*80,width=100,height=80)
#R4
But7=Button(root,text='7',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-4*80,width=80,height=80)
But8=Button(root,text='8',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-4*80,width=80,height=80)
But9=Button(root,text='9',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-4*80,width=80,height=80)
But_add=Button(root,text='+',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-4*80,width=100,height=80)
mainloop()
#输出面板
面板上数据需要保持实时的更新,这个使用Tkinter中的StringVar()可以实现
result = StringVar()
result.set('这里是result')
process = StringVar()
process.set('这是process')
我们创建StringVar()类型的两个参数result和process,其中result用于储存结果,process用于储存表达式
StringVar有get()和set()函数,get()为读取值,set()为赋值
将两个变量镶入Label中
Label(root,anchor = 'se',font = ('微软雅黑',30),textvariable = result).place(y=200,width=340,height=50)
Label(root,anchor = 'se',font = ('微软雅黑',20),textvariable = process).place(width=340,height=200)
这里用到的Label参数:
anchor表示设置显示位置,s代表south,e代表east,se即我们在东南(右下)显示内容,同理还有‘n’, ‘s’, ‘e’, ‘w’, ‘nw’, ‘sw’, ‘se’, ‘ne’, ‘center’这些参数可选,默认为center
font等功能同Button
加上面板之后:
from tkinter import *
root = Tk() #创造窗口
root.title("计算器") #更改标题
root.resizable(0,0) #窗口大小不可更改
root.geometry("340x720") #窗口大小
result = StringVar()
result.set('这里是result')
process = StringVar()
process.set('这里是process')
#R0
But_cmp=Button(root,text='=',font = ('微软雅黑',20),bg='orange').place(x=100,y=620,width=240,height=100)
But_point=Button(root,text='AC',font = ('微软雅黑',20),bg='orange').place(y=620,width=100,height=100)
#R1
But_AC=Button(root,text='.',bg='orange',font = ('微软雅黑',15)).place(x=0,y=620-1*80,width=80,height=80)
But0=Button(root,text='0',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-1*80,width=80,height=80)
But_back=Button(root,text='<--',bg='orange',font = ('微软雅黑',15)).place(x=0+2*80,y=620-1*80,width=80,height=80)
But_division=Button(root,text='/',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-1*80,width=100,height=80)
#R2
But1=Button(root,text='1',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-2*80,width=80,height=80) #command后直接跟需要参数的函数会报错
But2=Button(root,text='2',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-2*80,width=80,height=80)
But3=Button(root,text='3',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-2*80,width=80,height=80)
But_multi=Button(root,text='*',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-2*80,width=100,height=80)
#R3
But4=Button(root,text='4',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-3*80,width=80,height=80)
But5=Button(root,text='5',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-3*80,width=80,height=80)
But6=Button(root,text='6',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-3*80,width=80,height=80)
But_sub=Button(root,text='-',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-3*80,width=100,height=80)
#R4
But7=Button(root,text='7',bg='orange',font = ('微软雅黑',12)).place(x=0,y=620-4*80,width=80,height=80)
But8=Button(root,text='8',bg='orange',font = ('微软雅黑',12)).place(x=0+1*80,y=620-4*80,width=80,height=80)
But9=Button(root,text='9',bg='orange',font = ('微软雅黑',12)).place(x=0+2*80,y=620-4*80,width=80,height=80)
But_add=Button(root,text='+',font = ('微软雅黑',15),bg=('#969696')).place(x=0+3*80,y=620-4*80,width=100,height=80)
Label(root,anchor = 'se',font = ('微软雅黑',30),textvariable = result).place(y=200,width=340,height=50)
Label(root,anchor = 'se',font = ('微软雅黑',20),textvariable = process).place(width=340,height=200)
mainloop()
#运算功能实现
我们已经完成了整个面板的制作,最后就是面板背后,实现具体按键的功能了
算法很简单,将所有的输入传入到eval(),让编译器来运算,然后输出结果。
每按下一个按键,我们在Button中加入command参数,连接我们需要调用的函数,注意result和process是可以用来动态存储的,所以我们可以直接将表达式的输入储存在result中(第二个显示面板),在完成输入点击’=‘后,将整个result传入eval()得到结果即可。
注意一点,如果结果是无限小数(如1/3),面板会不够大,所以我采取保留六位小数的操作
if isinstance(ans,float):
ans=round(ans,6)
意为如果答案是float类型,则只保留6位小数
剩下的就是一些小细节的东西
如可以每次输入前检测面板目前的内容,如果为空可以显示善意的提示语句
如在一次运算完后,可以设定一个Flag用于标记,下次输入时清除面板数据,防止错误
......
#完整代码
from tkinter import *
root = Tk() #创造窗口
root.title("计算器") #更改标题
root.resizable(0,0) #窗口大小不可更改
root.geometry("340x720") #窗口大小
result = StringVar()
result.set('输入表达式...')
process = StringVar()
process.set('')
#R0
But_cmp=Button(root,text='=',font = ('微软雅黑',20),bg='orange',command=lambda:comput()).place(x=100,y=620,width=240,height=100)
But_point=Button(root,text='AC',font = ('微软雅黑',20),bg='orange',command=lambda:press('AC')).place(y=620,width=100,height=100)
#R1
But_AC=Button(root,text='.',bg='orange',font = ('微软雅黑',15),command=lambda:press('.')).place(x=0,y=620-1*80,width=80,height=80)
But0=Button(root,text='0',bg='orange',font = ('微软雅黑',12),command=lambda:press('0')).place(x=0+1*80,y=620-1*80,width=80,height=80)
But_back=Button(root,text='<--',bg='orange',font = ('微软雅黑',15),command=lambda:press('b')).place(x=0+2*80,y=620-1*80,width=80,height=80)
But_division=Button(root,text='/',font = ('微软雅黑',15),bg=('#969696'),command=lambda:press('/')).place(x=0+3*80,y=620-1*80,width=100,height=80)
#R2
But1=Button(root,text='1',bg='orange',font = ('微软雅黑',12),command=lambda:press('1')).place(x=0,y=620-2*80,width=80,height=80) #command后直接跟需要参数的函数会报错
But2=Button(root,text='2',bg='orange',font = ('微软雅黑',12),command=lambda:press('2')).place(x=0+1*80,y=620-2*80,width=80,height=80)
But3=Button(root,text='3',bg='orange',font = ('微软雅黑',12),command=lambda:press('3')).place(x=0+2*80,y=620-2*80,width=80,height=80)
But_multi=Button(root,text='*',font = ('微软雅黑',15),bg=('#969696'),command=lambda:press('*')).place(x=0+3*80,y=620-2*80,width=100,height=80)
#R3
But4=Button(root,text='4',bg='orange',font = ('微软雅黑',12),command=lambda:press('4')).place(x=0,y=620-3*80,width=80,height=80)
But5=Button(root,text='5',bg='orange',font = ('微软雅黑',12),command=lambda:press('5')).place(x=0+1*80,y=620-3*80,width=80,height=80)
But6=Button(root,text='6',bg='orange',font = ('微软雅黑',12),command=lambda:press('6')).place(x=0+2*80,y=620-3*80,width=80,height=80)
But_sub=Button(root,text='-',font = ('微软雅黑',15),bg=('#969696'),command=lambda:press('-')).place(x=0+3*80,y=620-3*80,width=100,height=80)
#R4
But7=Button(root,text='7',bg='orange',font = ('微软雅黑',12),command=lambda:press('7')).place(x=0,y=620-4*80,width=80,height=80)
But8=Button(root,text='8',bg='orange',font = ('微软雅黑',12),command=lambda:press('8')).place(x=0+1*80,y=620-4*80,width=80,height=80)
But9=Button(root,text='9',bg='orange',font = ('微软雅黑',12),command=lambda:press('9')).place(x=0+2*80,y=620-4*80,width=80,height=80)
But_add=Button(root,text='+',font = ('微软雅黑',15),bg=('#969696'),command=lambda:press('+')).place(x=0+3*80,y=620-4*80,width=100,height=80)
Label(root,anchor = 'se',font = ('微软雅黑',30),textvariable = result).place(y=200,width=340,height=50)
Label(root,anchor = 'se',font = ('微软雅黑',20),textvariable = process).place(width=340,height=200)
Flag = 0
def press(x):
global Flag
if Flag: #刚完成上一次运算,面板全部清除
result.set("输入表达式...")
process.set('')
Flag=0
if x == 'AC': #面板清除
if result.get() == "输入表达式...":
return
result.set("输入表达式...")
process.set('')
return
if x == 'b': #退位
if result.get() == "输入表达式...":
return
temp=result.get()[0:-1] #切片操作,保留面板字符串中下标0到倒数第二位(-1)的内容
if temp=='':
result.set('输入表达式...')
else:
result.set(temp)
return
if result.get()!='输入表达式...':
result.set(result.get()+x)
else:
result.set(x)
def comput():
expression = result.get()
ans = eval(expression)
process.set(expression+"=")
if isinstance(ans,float): #如果为小数,保留6位
ans=round(ans,6)
result.set(ans)
global Flag
Flag = 1 #标记完成了一次运算
mainloop()