zoukankan      html  css  js  c++  java
  • 如何用Tkinter写个计算器

    上机实践课程开始了,嗯,老师来了之后念了下PPT,然后说:开始做吧.........
    ennnn........就先别管老师怎么教了,PPT标注了可以不限语言

    然后就开始了Python的GUI之路,以前没接触过PYthon的可视化界面(虽然这样很不明智)
    但是现在做起来感觉写小工具还挺方便的,当时搜到的第一个库便是Tkinter就直接开始写了
    后来发现QT很不错的样子,下个实验就用QT吧.然后关于Tkinter(python3.6)

    计算器源码 ennn.....有的命名不规范.......

    首先对于python中栈的实现是通过list的方式模拟
    pop()出栈,append()入栈

    开始一个窗口

    做一个可视化的东西,首先想到的坑定是窗口吧
    窗口又有很多构成,比如title,ico,size,bd,菜单等.

    import tkinter
    import os
    from tkinter import *
    
    class Calculator(object):
    	"""计算器"""
    	def __init__(self):
    		self.tk=tkinter.Tk() #实例化
    		self.tk.title('计算器')
    		self.tk.minsize(370,460)
    		self.tk.maxsize(400,400)
    		#也可以用self.tk.resizable(0, 0)来禁止调节大小
    		self.tk.iconbitmap(os.getcwd()+'/favicon.ico')
    
    	def start(self):
    		self.tk.mainloop()	
    
    if __name__ == '__main__':
    	NewCalculator=Calculator()
    	NewCalculator.start()
    

    这里就生成了一个基本的窗口,对于其中的mainloop()的作用
    如果我们删除它,窗口会一闪而过,它就是为了防止这种情况

    面板显示

    做成计算器之后坑定要先是计算结果,这里就需要生成显示面板
    当然我们也会很自然地联想到显示内容的字体设置等需求,具体事例在下面代码

    ....
    import tkinter.font as tkfont
    
    ....
    		#字体设置
    		self.EntryFont=tkfont.Font(self.tk,size=13)
    		self.ButtonFont=tkfont.Font(self.tk,size=12)
    		#面板显示
    		self.count=tkinter.StringVar()
    		self.count.set('0')
    		self.label=tkinter.Label(self.tk,bg='#EEE9E9',bd='3',fg='black',anchor='center',font=self.EntryFont,textvariable=self.count)
    		self.label.place(y=10,width=380,height=40)
    
    ....
    

    其中tkinter中面板Lable有一些参数,这里用到的基本上也可以满足常见的需求了
    其中bg是背景色,fg是前景色,改变内容的颜色,anchor是定位内容在面板中的位置,如下图

    方向 示例 表格
    nw n ne
    w center e
    sw s se

    关于面板以及后边的Button的定位,可以用很多方式,place可以准确的定位,也可以用pack(),grid()
    对于计算器place是更好的,能够准确定位每一个控件
    其中字体也可以直接在Lable()加参数,例如font=("Arial,6")
    textvariable相当于“监听”的作用,绑定tkinter中的string,就可以用set()的方式方便的改变面板的内容

    按钮,输入框设置

    按钮,输入框的参数和面板里面的是相似的

    self.NumButton=tkinter.Button(master=self.tk,relief=GROOVE,bg='#EE6A50',text=self.ButtonList[0],
    			font=self.ButtonFont,command=self.clear)
    self.NumButton.place(x=30,y=80,width=70,height=55)
    
    self.shiEntry=Entry(self.baoxianTk,validate='key',validatecommand=(self.checkNum,'%P'),font=self.EntryFont)
    self.shiEntry.place(x=190,y=80)
    

    一样的是通过bg等参数设置基础的样式,只不过这里会通过command绑定事件,类似于JQ中的.click
    这里的place也是为了能够准确定位才使用的,其中的relief代表着Button的样式
    relief=FLAT or GROOVE or RAISED or RIDGE or SOLID or SUNKEN

    其中删除输入框的输入内容

    text.delete(10)  #删除索引值为10的值
    text.delete(10, 20)  #删除索引值从10到20之前的值
    text.insert(0, END)  #删除所有值
    

    输入限制

    在设计功能的时候我们可能需要用户输入数字等,这里可以进行限制一下
    Button参数中validate指定什么时候执行validatecommand绑定的函数,使用%P可以实时获取输入的内容
    当validate选项指定为key的时候,有任何的输入操作都会被拦截,这个时候返回True白能量才会输入到Entry

    self.checkNum=self.baoxianTk.register(self.validateNum)
    
    
    self.gerenEntry=Entry(self.baoxianTk,validate='key',validatecommand=(self.checkNum,'%P'),font=self.EntryFont)
    self.gerenEntry.place(x=190,y=190)
    
    
    #验证是否输入数字	
    def validateNum(self,content):
    	if content.isdigit() and int(content)>=0 or content=="":
    		return True
    	else:
    		return False
    

    validateNum()函数可以根据自己的需求进行更改
    启用验证validate选项可以设置的值有:

    名称 事件
    focus 当 Entry 组件获得或失去焦点的时候验证
    focusin 当 Entry 组件获得焦点的时候验证
    focusout 当 Entry 组件失去焦点的时候验证
    key 当输入框被编辑的时候验证
    all 当出现上边任何一种情况的时候验证

    拓展符号设计

    这个小计算器中我增加了%,/,sqrt三个符号
    对于他们的实现我的思路是添加到面板之前检测一下传入的button内容
    如果是这三种符号则做出对应的处理

    其中需要注意如果是多位数或者带有符号式子
    不能直接进行变换,需要判断你要转置的数字的位数,我的具体方式如下

    	def checkList(self):
    		result=0
    		locate=-1
    		listSum=0
    		for length in range(0,len(self.inputlist)):
    			if re.findall(r'[-+*/]',str(self.inputlist[length])):
    				result=1
    				if length>locate:
    					locate=length
    			else:
    				pass
    		if result==1:
    			for i in range(locate+1,len(self.inputlist)):
    				listSum+=int(self.inputlist[i])*(10**(len(self.inputlist)-i-1))
    		else:
    			for j in range(0,len(self.inputlist)):
    				listSum+=int(self.inputlist[j])*(10**(len(self.inputlist)-j-1))
    		return listSum,locate
    	#添加button
    	def addButton(self,button):
    		if button==self.ButtonList[18]:
    			listSum,locate=self.checkList()
    			if locate==-1:
    				self.inputlist=[str(round(eval('1/'+str(listSum)),5))]
    			else:
    				for k in range(locate+1,len(self.inputlist)):
    					del self.inputlist[k]
    				self.inputlist.append(str(round(eval('1/'+str(listSum)),5)))
    		elif button==self.ButtonList[19]:
    			pass
    		elif button==self.ButtonList[20]:
    			pass
    		else:
    			self.inputlist.append(button)
    		self.count.set(self.inputlist)
    

    关于lambda

    百度百科:Lambda表达式是Python中一类特殊的定义函数的形式,使用它可以定义一个匿名函数
    与其它语言不同,Python的Lambda表达式的函数体只能有唯一的一条语句,也就是返回值表达式语句

    搜索更多文章后理解更多,Lambda函数可以说是对按钮起到“call back”的作用
    如果我们不使用Lambda进行中间函数的延迟回调,在创建按钮的同时command绑定的函数会被调用
    即如下面两句代码的区别,第二句在进行创建时会直接执行knobDown函数

    self.NumButton=tkinter.Button(master=self.tk,relief=GROOVE,bg='#BFEFFF',text=self.ButtonList[20],
    			font=self.ButtonFont,command=lambda:self.knobDown(self.ButtonList[20]))
    self.NumButton=tkinter.Button(master=self.tk,relief=GROOVE,bg='#BFEFFF',text=self.ButtonList[20],
    			font=self.ButtonFont,command=self.knobDown(self.ButtonList[20]))
    

    更详细的解释可以参考文末最后两个文章,还是前辈写得好

    关于单选框

    本来想实现PPT中给出的示例-房贷计算的拓展,但是一直这个单选框产生BUG就放弃了
    下面的示例是从网上摘抄过来的,具体的网址忘了
    就是通过variable绑定一个IntVar(),通过.get()方式可以获取Radiobutton中value的值

    #!/usr/bin/env python
    import tkinter
    from tkinter import *
    import tkinter.font as tkfont
    
    
    root=tkinter.Tk()
    
    val=tkinter.IntVar()
    
    val.set(0)
    
    def func1():
        if val.get() == 0:
            label.configure(text='radio 0')
        else:
            label.configure(text='radio 1')
    
    label = tkinter.Label(root, text='radio 0')
    label.pack()
    r0 = tkinter.Radiobutton(text = 'radio0', variable = val, value = 0)
    r0.pack()
    r1 = tkinter.Radiobutton(text = 'radio1', variable = val, value = 1)
    r1.pack()
    b = tkinter.Button(root, text='button', command=func1)
    b.pack()
    
    root.mainloop()
    

    实现

    打包

    C:UsersayiDesktopshiyanprogrem
    (venv) λ pip install pyinstaller
    
    C:UsersayiDesktopshiyanprogrem
    (venv) λ pyinstaller -F -w -i favicon.ico run.py
    

    一开始因为代码中的设置ico图标为下面代码第一行
    windows下打包路径识别有问题,把图标换到一个路径短的地方
    修改成绝对路径就OK了(下面代码第二行,exe和ico要放在同一个目录下

    self.baoxianTk.icobitmap('favicon.ico')
    
    self.baoxianTk.iconbitmap(os.getcwd()+'/favicon.ico')
    

    效果预览

    虽然是现学现卖和对于别人的老知识,但是成功之后还是挺有成就感的(and我似乎对美工要求挑剔........
    调颜色和样式能挑半天,包括以前的那个爬虫的前端

    预览

    参考:Tkinter控件详解
    Python数据结构——栈
    创建一个只能输入数字的输入框
    Tkinter教程之Entry篇
    另一个Lambda表达式教程
    《Python编程》笔记(七)

  • 相关阅读:
    1 外部JavaScript
    1 外部JavaScript
    蓝桥杯:位运算
    Java为什么要配置环境变量
    java数组静态复制和动态复制越界问题
    Dijkstra算法java实现
    离散二元关系实验java实现
    Java中字符串split() 的使用方法
    用java编程实现集合的交、并、差和补运算
    61根据字符出现频率排序(451)
  • 原文地址:https://www.cnblogs.com/bay1/p/10982489.html
Copyright © 2011-2022 走看看