列表选择框Listbox绘制
列表选择框类似于单选框,绘制时使用Listbox类,并依附于一个窗体上:
listchoice=Listbox(rootWindow)
在创建了列表选项框后,使用listvariable对列表内容赋值,并可设置选择模式selectmode,单选为browse或single,多选为multiple。选择到某一项后,还需要添加事件响应,因此对整个列表选项框使用bind方法,绑定事件类型ListboxSelect及对应的响应。如下代码实践:
from tkinter import * root=Tk() root.geometry('300x400') root.wm_title('hello,python') label=Label(root,text='编程语言选择:') label.place(x=10,y=10) #使用place来布局 #准备好多项选择项,使用列表来设置 choiceList=['python','php','java','go'] #使用tkinter中的StringVar类设定选项所在的值,将其与列表框中的listvariable绑定关联 list1=StringVar(value=choiceList) #定义列表项 def show_msg(*args): #定义响应函数 indexs = choice1.curselection() #定义列表项所在的索引,返回索引列表 index = int(indexs[0]) #取得当前项的索引号 label1['text']="您的选项为: " +str(index) #设置当前索引号为label1标签内容 #列表选择创建及布局 choice1=Listbox(root,listvariable=list1,height=len(choiceList),selectmode='browse') choice1.place(x=120,y=10) choice1.bind("<<ListboxSelect>>",show_msg) #绑定选择对应的响应函数 #显示选中内容 label1=Label(root) label1.place(x=10,y=100) root.mainloop()
执行后效果如图:
组合选择框Combobox绘制
Combobox控件属于ttk模块类中的元素,因此在绘制组合选择框时需要导入ttk模块,然后使用ttk.Combobox(rootWindow)方法来完成。即:
cmb=ttk.Combobox(rootWindow)
其属性主要包括: value--选择列表内容。添加事件响应时使用bind函数,对整个组合框对象设置ComboboxSelected动作。如果要获得选择的内容,可以使用cmb对象的.get方法。如下代码实践:
from tkinter import * #导入ttk模块,Combobox控件属于ttk模块的对象 from tkinter import ttk root=Tk() root.geometry('300x400') root.wm_title('hello,python') label=Label(root,text='编程语言选择:') label.place(x=10,y=10) #定义选择响应函数 def callback(*args): text=choice1.get() label1['text']="您的选项为: " +text #组合框创建及布局 choice1=ttk.Combobox(root) choice1['value']=['python','php','java','go'] choice1.place(x=120,y=10) choice1.bind("<<ComboboxSelected>>",callback) #显示选中内容 label1=Label(root) label1['text']="您的选项为: " label1.place(x=10,y=40) root.mainloop()
执行后效果如图:
(3)菜单类控件设计
通常对于一个窗体应用程序而言,菜单是非常重要的构成部分。通过选择菜单,来完成对应的操作。因此在开发这类窗体时,主要关心菜单及其子菜单如何生成、菜单的点击事件响应。至于菜单的布局,默认会放在窗体的顶端,不过也可以通过后续布局来修改。例如python自带的IDLE:
主菜单创建Menu
在窗体上绘制菜单时,使用Menu类,并将创建的菜单实例与窗体进行绑定。即:
mainMenu=Menu(root) #指定父级窗口 root(menu=mainMenu) #在父级窗口里设定menu属性
有了主菜单对象后,就可以使用add_command方法将菜单标签内容及响应函数添加到主菜单中。 add_command 中的参数常用的有 label 属性,用来指定的 是菜单项的名称,command 属性用来指定被点击的时候调用的方法, acceletor 属性指定的是快捷键,underline 属性是否拥有下划线。
例如创建如IDLE主菜单代码:
from tkinter import * root=Tk() root.wm_title('hello,python') root.geometry('400x200') #主菜单内容列表 mainMenuList=['File','Edit','Format','Run','Options','Window','Help'] #在root窗体中创建菜单,返回menubar对象 menubar=Menu(root) #给每个主菜单添加标签内容 for item in mainMenuList: menubar.add_command(label=item) #配置父级root窗体的menu属性 root['menu']=menubar root.mainloop()
执行后效果如下:
效果与IDLE基本一致。
子菜单创建
接下来我们添加一下子菜单。一般情况下主菜单都仅仅是标签内容显示,实际执行菜单多放置在子菜单内。添加子菜单时也需要指定子菜单的父级控件,例如要是Help菜单下创建子菜单,那Help菜单就是其子菜单的父级控件。在子菜单中需要给定点击响应函数,一般情况下点击响应函数都会不一样,因此在实际开发代码的时候需要单独给定,如下代码实践:
from tkinter import * root=Tk() root.wm_title('hello,python') root.geometry('400x200') #创建root窗体里的菜单对象,同时添加主菜单内容 menubar=Menu(root) menubar.add_cascade(label='File') menubar.add_cascade(label='Edit') menubar.add_cascade(label='Format') menubar.add_cascade(label='Run') menubar.add_cascade(label='Options') menubar.add_cascade(label='Window') #定义help子菜单回调函数 def toAbout(): label['text']='当前选中的子菜单为:'+helpMenu[0] def toHelp(): label['text']='当前选中的子菜单为:'+helpMenu[1] def toDoc(): label['text']='当前选中的子菜单为:'+helpMenu[2] def toTurtle(): label['text']='当前选中的子菜单为:'+helpMenu[3] #构建help主菜单及其子菜单内容,例如构建help菜单及其子菜单 helpMenu=['About IDLE','IDLE Help','Python Docs F1','Turtle Demo'] hmenu=Menu(menubar) hmenu.add_command(label=helpMenu[0],command=toAbout) hmenu.add_command(label=helpMenu[1],command=toHelp) hmenu.add_command(label=helpMenu[2],command=toDoc) hmenu.add_command(label=helpMenu[3],command=toTurtle) #构建help主菜单,同时添加子菜单 menubar.add_cascade(label='Help',menu=hmenu) root['menu']=menubar #在窗体内增加一个标签,显示当前选中的菜单内容 label=Label(root) label.pack() #主窗体循环,启动显示 root.mainloop()
上面的代码仅仅对help主菜单添加了子菜单,同时给每个子菜单添加了点击事件响应,效果如下:
如果要完成类似IDLE窗体,还差一个文本输入框和右侧的滚动侧边栏。我们试着添加一下,代码如下:
from tkinter import * root=Tk() root.wm_title('hello,python') root.geometry('400x200') #创建root窗体里的菜单对象,同时添加主菜单内容 menubar=Menu(root) menubar.add_cascade(label='File') menubar.add_cascade(label='Edit') menubar.add_cascade(label='Format') menubar.add_cascade(label='Run') menubar.add_cascade(label='Options') menubar.add_cascade(label='Window') #定义help子菜单回调函数 def toAbout(): label['text']='当前选中的子菜单为:'+helpMenu[0] def toHelp(): label['text']='当前选中的子菜单为:'+helpMenu[1] def toDoc(): label['text']='当前选中的子菜单为:'+helpMenu[2] def toTurtle(): label['text']='当前选中的子菜单为:'+helpMenu[3] #构建help主菜单及其子菜单内容,例如构建help菜单及其子菜单 helpMenu=['About IDLE','IDLE Help','Python Docs F1','Turtle Demo'] hmenu=Menu(menubar) hmenu.add_command(label=helpMenu[0],command=toAbout) hmenu.add_command(label=helpMenu[1],command=toHelp) hmenu.add_command(label=helpMenu[2],command=toDoc) hmenu.add_command(label=helpMenu[3],command=toTurtle) #构建help主菜单,同时添加子菜单 menubar.add_cascade(label='Help',menu=hmenu) root['menu']=menubar #在窗体内增加一个文本框,右侧为滚动侧边栏,同时将滚动栏与文本框内容绑定显示 TextArea=Text(root) TextArea.pack(side='left',fill=Y) scrollbtn=Scrollbar(root) scrollbtn.pack(side='right',fill=Y) TextArea.config(yscrollcommand=scrollbtn.set) scrollbtn.config(command=TextArea.yview) #主窗体循环,启动显示 root.mainloop()
再来运行,效果如图:
(4)Frame控件
Frame就是框架容器,可以在里面添加各种控件,其实root根窗体就是一个大的Frame。在tkinter里有单独的Frame类,使用Frame类方法就可以创建一个frame,然后设置其布局方式。
我们先来进行实践,而后解释:
from tkinter import * root=Tk() root.wm_title('hello,python') root.geometry('400x200') root.resizable(0,0) label=Label(root,text='frame框架的例子').pack() #左侧新建一个frame容器,里面放置单选框 frm1=Frame(root,width=100,height=200,bg='#ddd') frm1.pack(side='left',fill=Y) label=Label(frm1,text='请选择',bg='#ddd',font=15) label.place(x=5,y=5) #准备好单选内容列表 choiceList=[('米老鼠',1),('唐老鸭',2),('猪八戒',3),('孙悟空',4)] #引入IntVar类,存储全局的v变量值 v=IntVar() v.set(1) #设置v值为1,即默认选择为第一项 #单选时回调函数 def callback(): value=v.get() if value==1: label2['text']="唐老鸭,即唐纳德。(英文名称:Donald Fauntleroy Duck)是 \ 迪士尼所创的经典卡通萌星之一,官方生日是1934年6月9日,\ 首次出现在《聪明的小母鸡》里。它有橙黄色的嘴、脚和蹼,\ 身上穿的是方特罗伊水手装,但没有穿裤子" elif value ==2: label2['text']="米奇老鼠(英文名称:Mickey Mouse),迪士尼代表人物形象,是一只 \ 有着圆滚滚的大脑袋,圆滚滚的大耳朵,梨形的身体与像橡胶 \ 软管一样柔软,没有明显的关节,可以自由拉伸仿佛没有骨骼 \ 的四肢的小老鼠。" elif value ==3: label2['text']=" 孙悟空是中国著名的神话人物之一,出自四大名著之《西游记》。祖籍 \ 东胜神州,由开天辟地以来的仙石孕育而生,因带领群猴进入 \ 水帘洞而成为众猴之王,尊为 “美猴王”。" elif value ==4: label2['text']= "猪八戒是明朝小说家吴承恩所作《西游记》中登场的虚拟角色。又名猪 \ 刚鬣,法号悟能(观音取),浑名八戒(唐僧取),是唐僧的 \ 二徒弟,会天罡数的三十六般变化,所持武器为太上老君所造 \ 、玉皇大帝亲赐的上宝沁金钯(俗称九齿钉耙)" #在左侧frame中设置单选项 for item,value in choiceList: radioChoice=Radiobutton(frm1,bg='#ddd',font=(14)) radioChoice['text']=item radioChoice['variable']=v radioChoice['value']=value radioChoice['command']=callback radioChoice.place(x=5,y=10+value*25) #右侧新建一个frame容器,里面放置标签 frm2=Frame(root,width=298,height=150,bg='lightgreen',relief='groove') frm2.pack(side='left',fill=Y) label2=Label(frm2,font=16,anchor="w", justify="left",wraplength=300,bg='lightgreen') label2.place(x=1,y=1)
运行后效果如图:
我在上述案例中布局顺序为:先布局一个标签,内容为“frame框架的例子", 采用pack方法布局,让其占满第一行并居中显示;然后布局两个frame,一个在左侧,一个在右侧,左侧frame中构建单选列表,右侧frame中构建一个label标签,用于左侧frame中单选框选择时,其text属性为关联的内容。
从代码看来,创建frame的方式为:
fm=Frame(rootWindow) #创建frame fm.pack() #实现窗体布局方式
创建了frame后,就可以将其作为一个父级容器,在里面可以绘制其他控件,如绘制一个label标签,就可以使用如下代码:
label=Label(fm) #以frame为父级容器创建label标签 label.place(x=0,y=0) #建议采用place方式布局更为精确
(5)Canvas控件
与Frame类似,Canvas也是一种框架容器,可以在里面添加各种控件,不过canvas从字面意思是画布,所以主要使用canvas容器在上面进行图形绘制。这里的图形包括直线、椭圆、多边形、图片等多种类型,主要使用方式为:
canvas=Canvas(rootWindow,width=500,height=300) #在父级容器中创建一个画布 canvas.pack()
有了画布,就可以在上面绘制多种图形了,主要使用方式如下:
canvas.create_line(0,0,100,100,fill='blue') #绘制一个直线,给定起始和终点坐标,fill表示填充颜色 canvas.create_polygon(0,0,100,100,200,130) #绘制一个polygon,需要至少三个点坐标 canvas.create_oval(20,20,40,40) #绘制一个椭圆 canvas.create_rectangle(10,10,300,250) #绘制多边形
下面我以上述frame布局案例为基础,修改一下代码,左侧frame仍为单选项,设置为绘制图形的类型,右侧frame中创建一个画布,然后根据左侧的选择在上面绘制不同的图形。
from tkinter import * import time #导入time时间包 import random #导入随机模块 root=Tk() root.wm_title('hello,python') root.geometry('400x200') root.resizable(0,0) label=Label(root,text='canvas的例子').pack() #左侧新建一个frame容器,里面放置单选框 frm1=Frame(root,width=100,height=200,bg='#ddd') frm1.pack(side='left',fill=Y) label=Label(frm1,text='请选择类型',bg='#ddd',font=15) label.place(x=5,y=5) #准备好单选内容列表 choiceList=[('画直线',1),('画多边形',2),('画椭圆',3),('动画示例',4)] #引入IntVar类,存储全局的v变量值 v=IntVar() v.set(1) #设置v值为1,即默认选择为第一项 #单选时回调函数 def callback(): value=v.get() if value==1: canvas.delete(ALL) #清除画布 canvas.create_line(1,1,120,120,fill='red') #画直线 elif value ==2: canvas.delete(ALL) canvas.create_polygon(10,10,120,120,200,80,fill='blue') #画polygon,并充填 elif value ==3: canvas.delete(ALL) canvas.create_oval(50,50,70,70,fill='purple') #画一个圆 elif value ==4: canvas.delete(ALL) canvas.create_oval(50,50,70,70,fill='red') #画一个圆,当画布的位置设定时间循环移动时就可以形成动画 for i in range(0,60): #设定一共循环60次 dx=random.randint(-15,15) #x方向随机变化取值 dy=random.randint(-13,13) #y方向随机变化取值 canvas.move(1,dx,dy) #按设定的x和y变动方向移动画布 frm2.update() #移动后frm2容器刷新 time.sleep(0.25) #间隔0.25秒后进入下一次循环 #在左侧frame中设置单选项 for item,value in choiceList: radioChoice=Radiobutton(frm1,bg='#ddd',font=(14)) radioChoice['text']=item radioChoice['variable']=v radioChoice['value']=value radioChoice['command']=callback radioChoice.place(x=5,y=10+value*25) #右侧新建一个frame容器,里面放置画布 frm2=Frame(root,width=300,height=200,bg='lightgreen',relief='groove') frm2.pack(side='left',fill=Y) canvas=Canvas(frm2,width=298,height=198) #创建一个画布 canvas.place(x=1,y=1) #画布以父级容器为参考,左上角坐标为1,1
执行代码,效果如图:
由此可以使用tkinter及画布组合来设计很多好玩的小游戏呢。
至此本文就tkinter的窗体设计开发方面进行了主要功能的介绍,还有一些如开篇介绍的颜色选择器、文件选择器、ttk、tix等模块都未涉及,后续再进行爬虫软件开发时再来详细介绍,有兴趣的同学也可以自行查询tkinter文档来实际体验。