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

Entry组件

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

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

1 from tkinter import *
2 
3 root = Tk()
4 e = Entry(root)
5 e.pack(padx=20,pady=20)
6 e.delete(0,END)
7 e.insert(0,"默认文本。。。")
8 mainloop()

如图所示:

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

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

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

执行结果:

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

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

 1 from tkinter import *
 2 
 3 root = Tk()
 4 Label(root,text="账号:").grid(row=0)
 5 Label(root,text="密码:").grid(row=1)
 6 v1 = StringVar()
 7 v2 = StringVar()
 8 e1 = Entry(root,textvariable=v1)
 9 e2 = Entry(root,textvariable=v2,show="*")
10 e1.grid(row=0,column=1,padx=10,pady=5)
11 e2.grid(row=1,column=1,padx=10,pady=5)
12 def show():
13     print("账号:%s"%v1.get())
14     print("作者:%s"%v2.get())
15     e1.delete(0,END)
16     e2.delete(0,END)
17 Button(root,text="芝麻开门",width=10,command=show).grid(row=3,column=0,sticky=W,padx=10,pady=5)
18 Button(root,text="退出",width=10,command=root.quit).grid(row=3,column=1,sticky=E,padx=10,pady=5)
19 mainloop()

 

执行结果:

 

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

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

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

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

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

 1 from tkinter import *
 2 root = Tk()
 3 def test():
 4     if e1.get() =="python3":
 5         print("正确")
 6         return True
 7     else:
 8         print("错误")
 9         e1.delete(0,END)
10         return False
11 v1 = StringVar()
12 e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test)
13 e2 = Entry(root)
14 e1.pack(padx=10,pady=10)
15 e2.pack(padx=10,pady=10)
16 mainloop()

执行结果:

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

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

 1 from tkinter import *
 2 root = Tk()
 3 def test():
 4     if e1.get() =="python3":
 5         print("正确")
 6         return True
 7     else:
 8         print("错误")
 9         e1.delete(0,END)
10         return False
11 def test2():
12     print("我被调用了。。。")
13     return True
14 v1 = StringVar()
15 # e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test)
16 e1 = Entry(root,textvariable=v1,validate="focusout",validatecommand=test,invalidcommand=test2)
17 e2 = Entry(root)
18 e1.pack(padx=10,pady=10)
19 e2.pack(padx=10,pady=10)
20 mainloop()

执行结果:

其实,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()方法将验证函数包装起来。

 1 from tkinter import *
 2 root = Tk()
 3 v = StringVar()
 4 def test(content,reason,name):
 5     if content =="python3":
 6         print(content,reason,name)
 7         return True
 8     else:
 9         print("错误")
10         print(content,reason,name)
11         return False
12 testCDM = root.register(test)
13 e1 = Entry(root,textvariable=v,validate="focusout",validatecommand=(testCDM,'%P','%v','%W'))
14 e2 = Entry(root)
15 e1.pack(padx=10,pady=10)
16 e2.pack(padx=10,pady=10)
17 mainloop()

执行结果:

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

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

执行结果:

 

 Listbox组件

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

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

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

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

执行结果:

使用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个怎么办了

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

执行结果:

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

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

执行结果:

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

Scrollbar组件

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

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

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

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

 1 if __name__ == "__main__":
 2     from tkinter import *
 3     master = Tk()
 4     sb = Scrollbar(master)
 5     sb.pack(side=RIGHT,fill=Y)
 6     lb = Listbox(master,yscrollcommand=sb.set)
 7     for i in range(100):
 8         lb.insert(END,str(i))
 9     lb.pack()
10     sb.config(command=lb.yview)
11     mainloop()

执行结果:

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

Scale组件

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

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

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

执行结果:

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

 1 if __name__ == "__main__":
 2     from tkinter import *
 3     root = Tk()
 4     s1 = Scale(root, from_=0, to=20)
 5     s1.pack()
 6     s2 = Scale(root, from_=0, to=200, orient=HORIZONTAL)
 7     s2.pack()
 8 
 9     def show():
10         print(s1.get(),s2.get())
11     Button(root,text="获取位置",command=show).pack()
12 
13     mainloop()

执行结果:

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

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

执行结果:

 

posted @ 2018-11-12 21:48  阳光宝贝-沐沐  阅读(2319)  评论(0编辑  收藏  举报