GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

Entry组件

Entry组件就是平时所说的输入框。输入框是程序员用到的最多的一个程序,例如在输入账号和密码的时候需要提供两个输入框,用于接收密码的输入框还会有星号将实际输入的内容隐藏起来。

Tkinter组件之间的许多方法和选项之间都是通用的,例如在输入框中用代码添加删除内容,同样也是使用insert()和delete()方法

 from tkinter import *

 root = Tk()
e = Entry(root)
e.pack(padx=20,pady=20)
e.delete(0,END)
e.insert(0,"默认文本。。。")
mainloop()

如图所示:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

获取输入框里面的内容,可以使用Entry组件的get()方法。当然也可以将一个Thinter的变量(通常是StringVar)挂钩到textvariablex选项,然后通过变量的get()方法获取。

继续看下面的例子,添加一个按钮,当单击按钮时候,获取输入框的内容并打印出来,然后清空输入框。单击“获取信息”按钮,在IDIE中输入框中的内容显示出来。

 from tkinter import *

 root = Tk()
#Tkinter总共提供了三种布局方法:pack(),grid()和place()
#grid()方法允许你用表格的形式爱管理组件的位置
#row选项代表行,column选项代表列
#例如:row=1,column=2表示第二行第三列(0表示第一行)
Label(root,text="作品:").grid(row=0)
Label(root,text="作者:").grid(row=1)
e1 = Entry(root)
e2 = Entry(root)
e1.grid(row=0,column=1,padx=10,pady=5)
e2.grid(row=1,column=1,padx=10,pady=5)
def show():
print("作品:《%s》"%e1.get())
print("作者:%s"%e2.get())
e1.delete(0,END)
e2.delete(0,END)
#如果表格大于组件,那么可以使用sticky选项来设置组件的位置
#同样需要使用N,E,S,W以及他们的组合NE,SE,SW,NW来表示方位
Button(root,text="获取信息",width=10,command=show).grid(row=3,column=0,sticky=W,padx=10,pady=5)
Button(root,text="退出",width=10,command=root.quit).grid(row=3,column=1,sticky=E,padx=10,pady=5)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

如果你手残的话,肯定会发现单击 “退出”按钮没有反应,这是因为python的IDIE也是使用Tkinter设计的,因此当程序使用IDIE运行的时候,就会出现此类冲突,解决方法:在cmd中运行脚本

如果想设计一个密码输入框,即使用星号(*)代替用户输入的内容,只需要设计show选项即可。

 from tkinter import *

 root = Tk()
Label(root,text="账号:").grid(row=0)
Label(root,text="密码:").grid(row=1)
v1 = StringVar()
v2 = StringVar()
e1 = Entry(root,textvariable=v1)
e2 = Entry(root,textvariable=v2,show="*")
e1.grid(row=0,column=1,padx=10,pady=5)
e2.grid(row=1,column=1,padx=10,pady=5)
def show():
print("账号:%s"%v1.get())
print("作者:%s"%v2.get())
e1.delete(0,END)
e2.delete(0,END)
Button(root,text="芝麻开门",width=10,command=show).grid(row=3,column=0,sticky=W,padx=10,pady=5)
Button(root,text="退出",width=10,command=root.quit).grid(row=3,column=1,sticky=E,padx=10,pady=5)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

另外,Entry组件还支持验证输入内容的合法性,例如输入框要求输入的是数字,用户输入了字母就输入“非法”操作了,实现该功能需要通过设置validate,validatecommand和invalidcommand三个选项。

首先是启用验证的“开关”是validate选项,该选项可以设置的值如下表所示:

含义
focus 当Entry组件获取或失去焦点的时候验证
focusin 当Entry组件获得焦点的时候验证
focusout 当Entry组件失去焦点的时候验证
key 当输入框被编辑的时候验证
all 当出现上面任何一种情况的时候验证
none 当关闭验证功能。默认设置该选项(即不启动验证)。注意,是字符串的‘none’,而非None

其次是validatecommand选项指定一个验证函数,该函数只能返回True或False表示验证的结果。一般情况下验证函数只需要知道输入框的内容即可。可以通过Entry组件的get()方法获得该字符串。

下面的例子中,在第一个输入框中输入“python3”并通过Tab键将焦点转移到第二个输入框的时候,验证功能被成功触发:

 from tkinter import *
root = Tk()
def test():
if e1.get() =="python3":
print("正确")
return True
else:
print("错误")
e1.delete(0,END)
return False
v1 = StringVar()
e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test)
e2 = Entry(root)
e1.pack(padx=10,pady=10)
e2.pack(padx=10,pady=10)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

最后,invalidcommand选项指定的函数只有在validatecommand的返回值为False的时候才会被调用。

在下面的例子中,在第一个输入框中输入的“python3”,并通过Tab键将焦点转移到第二个输入框,validatecommand指定的验证函数被触发并返回False,接着invalidatecommand被触发。

 from tkinter import *
root = Tk()
def test():
if e1.get() =="python3":
print("正确")
return True
else:
print("错误")
e1.delete(0,END)
return False
def test2():
print("我被调用了。。。")
return True
v1 = StringVar()
# e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test)
e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test,invalidcommand=test2)
e2 = Entry(root)
e1.pack(padx=10,pady=10)
e2.pack(padx=10,pady=10)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

其实,Tkinter还有个一“隐藏技能”,Tkinter为了验证函数提供 了一些额外的选项,如下表

选项 含义
%d 操作代码,0表示删除操作,1表示插入操作,2表示获得、失去焦点或textvariable变量的值被修改
%r 当用户尝试插入或删除操作的时候,该选项表示插入或删除的位置(索引号)如果是由于获得、失去焦点或textvariable变的值被修改而调用验证函数,那么该值是-1
%p 当输入框的值允许改变的时候,该值有效,该值为输入框的最新文本内容
%s 该值为调用验证函数前输入框的文本内容
%S 当插入或删除操作触发验证函数的时候,该值有效选项表示文本被插入和删除的内容
%v 该组件当前的validate选项的值
%V 调用验证函数的原因该值是focusin,focusout,key或forced(textvariable选项指定的变量值被修改)中一个
%W 该组件的名字

为了使用这些选项,你也可以这样写:

validatecommand = (f,s1,s2,...)

其中,f是验证函数名,s1,s2等是额外的选项,这些选项会作为参数一次性传递给f函数。在此之前,需要调用register()方法将验证函数包装起来。

 from tkinter import *
root = Tk()
v = StringVar()
def test(content,reason,name):
if content =="python3":
print(content,reason,name)
return True
else:
print("错误")
print(content,reason,name)
return False
testCDM = root.register(test)
e1 = Entry(root,textvariable=v,validate="focusout",validatecommand=(testCDM,'%P','%v','%W'))
e2 = Entry(root)
e1.pack(padx=10,pady=10)
e2.pack(padx=10,pady=10)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

下面我们来写一个简单的计算器

 from tkinter import *

 root = Tk()
frame = Frame(root)
frame.pack(padx=10,pady=10)
v1 = StringVar()
v2 = StringVar()
v3 = StringVar()
def test(content):
#注意,这里不能使用e1.get()或者来获取输入的内容
#因为validate选项指定"key"的时候,有任何输入操作都会被拦截到这个函数中
#也就是说先拦截,只有这个函数返回True,那么输入的内容才会到变量里面
#所以要使用%P来获取最新的输入框内容
if content.isdigit():
return True
else:
return False
testCDM = root.register(test)
Entry(frame,textvariable=v1,width=10,validate='key',validatecommand=(testCDM,'%P')).grid(row=0,column=0)
Label(frame,text='+').grid(row=0,column=1)
Entry(frame,textvariable=v2,width=10,validate='key',validatecommand=(testCDM,'%P')).grid(row=0,column=2)
Label(frame,text='=').grid(row=0,column=3)
Entry(frame,textvariable=v3,width=10,validate='key',validatecommand=(testCDM,'%P')).grid(row=0,column=4)
def calc():
result = int(v1.get()) + int(v2.get())
v3.set(result)
Button(frame,text="计算器",command=calc).grid(row=1,column=2,pady=5)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

 Listbox组件

如果需要提供选择给用户选择,单选可以用Radiobutton组件,多选可以用Checkbutton组件。但是如果提供的选项非常多,例如选择你所在的城市,通过Radiobutton和Checkbutton组件来实现直接导致的结果就是,用户界面存放不了那么多按钮。

这个时候就需要考虑使用Listbox组件了,Listbox组件是以列表形式显示出来,并支持滚动操作,所以对于需要大量选项的情况下会更好用点。

当创建一个Listbox组件的时候,它是空的(里面什么都没有),所以,首先要做的第一个事情就是添加一行或多行文本进去。使用insert()方法添加两个参数:第一个参数是插入的索引号,第二个参数是插入的字符串。索引号通常是项目的序号(第一项的序号是0),当然对于多个项目,应该使用循环。

 from tkinter import *
master = Tk()
theLB = Listbox(master,setgrid=True) #创建一个空列表
theLB.pack()
#向列表中添加数据
for item in ["恐龙蛋","鹅蛋","鸭蛋","鸡蛋"]:
theLB.insert(END,item)
theButton = Button(master,text="删除",command=lambda x=theLB:x.delete(ACTIVE))
theButton.pack()
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

使用delete()方法删除列表中的项目,最常用的操作是删除列表中的所有项目:listbox.delete(0,END)

#跟END一样,这个AXTIVE是一个特殊的索引号,表示当前被选中项目
theButton = Button(master,text="删除",command=lambda x=theLB:x.delete(ACTIVE))
theButton.pack()

最后,这个Listbox组件根据selectmode选项提供了四种不同的选择模式:SINGLE(单选),BROWSE(也是单选,但拖动鼠标或通过方向键可以直接改变选项),MELTIPLE(多选)和EXTENDED(也是多选,但是需要同时按照Shift键或Ctrl键拖动光标实现)。默认的选中模式是BROWSE.

选项增多接踵而来的麻烦也会增多,例如使用Listbox组件默认只能显示10个项目,而有11个怎么办了

 from tkinter import *
master = Tk()
theLB = Listbox(master,setgrid=True) #创建一个空列表
theLB.pack()
#往列表中增加数据
for item in range(20):
theLB.insert(END,item)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

共有20个数字,但是只显示了10个,只能利用上下键或者鼠标滚动才能显示下面数字,如果想让下面的数字都显示,第一个方法就是修改height选项

theLB = Listbox(master,setgrid=True,height=14)

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

可以看到height选项虽然能达到目的,但是少了就不显示,多了就超出屏幕,所以我们可以用第二种方法就是在右边添加一个滚动条。

Scrollbar组件

滚动条是一个独立的组件,但是他平时都是和其他组件配合使用,下面一个例子看下如何使用垂直滚动条。

为了在某个组件上安装垂直滚动条,需要做两件事

1、设置组件的yscrollbarcommand选项Scrollbar组件的set()方法

2、设置Scrollbar组件的command选项为该组件的yview()方法

 if __name__ == "__main__":
from tkinter import *
master = Tk()
sb = Scrollbar(master)
sb.pack(side=RIGHT,fill=Y)
lb = Listbox(master,yscrollcommand=sb.set)
for i in range(100):
lb.insert(END,str(i))
lb.pack()
sb.config(command=lb.yview)
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

这是一个互联互通的过程,当用户操作滚动条进行滚动时,滚动条相应滚动并通过Listbox组件的yview()方法滚动列表框里的内容,同样,当列表框中可视范围发送改变的时候,Listbox也会相应的改变。

Scale组件

Scale组件和Scrolbar滚动条组件很相似,都可以滚动,都是条形,但是他们的使用范围是不相同的。Scale组件主要是通过修改选项设置范围以及分辨率(精度)。

当希望用户输入某个范围的数值,使用Scale组件可以很好地替代Entry组件,创建一个指定范围的Scale组件其实非常容易,只要指定from和to两个关键字即可,但是from本身是python的关键字,为了区分我们在后面加下划线from_

 if __name__ == "__main__":
from tkinter import *
root = Tk()
Scale(root,from_=0,to=20).pack()
Scale(root,from_=0,to=200,orient=HORIZONTAL).pack()
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

可以使用get()方法获取当前滑动的位置:

 if __name__ == "__main__":
from tkinter import *
root = Tk()
s1 = Scale(root, from_=0, to=20)
s1.pack()
s2 = Scale(root, from_=0, to=200, orient=HORIZONTAL)
s2.pack() def show():
print(s1.get(),s2.get())
Button(root,text="获取位置",command=show).pack() mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

可以通过resolution选项控制分辨率(步长),通过tickinterval选项设置刻度:

 from tkinter import *
root = Tk()
Scale(root,from_=0,to=20,tickinterval=5,resolution=5,length=200).pack()
Scale(root,from_=0,to=200,tickinterval=10,orient=HORIZONTAL,resolution=10,length=600).pack()
mainloop()

执行结果:

GUI的最终选择 Tkinter(四):Entry、Listbox、Scrollbar和Scale组件

 

上一篇:Python黑帽编程2.9 面向对象编程


下一篇:AI 信息论