python 窗口模块 python窗体模块_输入框


python是编程语言,如果要实现GUI窗体设计,还需要单独的GUI模块。 其余的编程语言里貌似除了微软系列产品外,其他的都得依赖于GUI设计软件。例如Java需要Swing工具包,go语言需要GTK等。对于Python而言,如果要开发窗体应用程序,除了借助于django或flask等与HTML前端技术结合外,同时也有一些GUI工具包可以使用,例如tkinter、wxpython,还可以使用pyQT来完成。


python 窗口模块 python窗体模块_控件_02


本篇以tkinter内置模块为例,介绍一下python窗体设计过程和方法。同时将以开发一个爬虫模块窗体实战为例,帮助大家快速上手实践。

(1)tkinter基本用法

tkinter是python内置的一个GUI开发模块,使用的时候直接使用import方法就可以导入该模块。


import tkinter
# 或者 from tkinter import *


如果有习惯读取该模块源代码的话,可以直接进入python安装目录下的Lib文件夹里,下面就是tkinter模块目录,打开后发现有如下py文件,功能简介如下:


python 窗口模块 python窗体模块_输入框_03


直接使用idle就可以打开这些py文件,当然读取源代码来理解还是比较痛苦的,还是上手实践来得快。

在spyder开发页面内或者IDLE内输入如下代码,启动第一个hello窗口:


import tkinter          #导入tkiner模块
root=tkinter.Tk()       #实例化一个窗体对象
root.wm_title('hello,python')     #设置该窗体的标题为hello,python
root.geometry('300x200')          #设置窗体大小为宽300,高200,中间用键盘上的x表示
root.mainloop()         #窗体对象运行,消息循环


运行后就会弹出第一个窗体hello:


python 窗口模块 python窗体模块_java中frame窗体星星坠落_04


这样我们就设计了一个窗体了。窗体也是一个二维平面容器,容器的意思就是里面可以放置其他的东西,对于窗体而言,可以依附在上的就是UI控件了。UI控件也就是窗体上那些基本元素,如标签、按钮、文本输入框、单选框、多选框、列表选择框、图片容器、表格等,英文名叫widgets。

如下窗体里就包括标签、按钮、输入框、列表选择框:


python 窗口模块 python窗体模块_控件_05


很显然,标签主要用于文本内容显示,如上面图片中的姓名、身高等信息;按钮就用于点击后形成触发事件,执行下一步的动作;输入框用于信息的输入,提供给使用者来进行输入;列表框、单选框、多选框属于同一类型,通过选择一种或者多种来准备下一步的事件。

对于python如果使用tkinter模块,上述图片中这些控件需要通过代码编写来实现,而不是如VB或者VC那样提供控件库,在窗体上拖拽即可快速实现布局。所以在实现控件的布局方面还是有一定挑战的,除了要使用代码生成这些控件外,还得使用代码来实现布局,也就是这些控件的摆放位置和顺序。好在是记住规律,多实践也能搞定。

(2)tkinter基本控件的绘制

下面我们来使用代码生成常用的控件,同时还需要使用布局方法。

绘制Label标签控件: Label(root)

标签是窗体中最基本的控件,用于清楚标注窗体各个组成部分的内容。在tkinter中采用Label函数来在窗体中设计标签,基本用法为:


label=Label( rootWindow) --   括号中的参数表示在rootWindow窗体上绘制Label标签,返回一个标签对象。


标签的基本属性包括:text -- 标签内容 ; font -- 字体属性 ; fg -- 字体颜色 ; bg -- 背景颜色 ; image -- 背景图片。配置这些基本属性时,可以与绘制标签一起,也可以后续配置。如果与创建标签同时配置属性,写法为:


label=Label(rootWindow,text = 'hello', fg= 'red' )


也可以将创建过程与配置属性过程分离,即:


label=Label(rootWindow)
label['text']='hello'


有了控件后,如何摆放布局也是需要设计的。在tkinter中有三种布局方法,pack、grid、place。

其中pack方法为自适应布局方法,即根据控件大小和顺序来自动实现布局,默认让一个控件独立占一行并居中显示,也可以加入参数调整位置,其基本用法为:


ui.pack()     #ui为控件名


或者:


ui1.pack(side='LEFT')    #设定ui显示在窗体左侧,这时右侧也需要有一个控件
ui2.pack(side='RIGHT')


grid方法为网格布局,即基于设定将窗体分割为相等大小的单元格,用行和列位置来布局控件,其基本用法为:


ui.grid(row=m,column=n)   #m,n为设定控件所在的行数和列数位置


place方法为空间布局,可以自由设定控件元素的起始x和y坐标:


ui.place(x=100,y=100)   #设定该控件左上角坐标为x:100,y:100


下面进入第一个示例事件,即在窗体上绘制一个标签,并设置基本属性和布局方式:


from tkinter import *
root=Tk()
root.wm_title('hello,python')
root.geometry('300x200')

#在窗体root上添加label标签
label=Label(root)           #调用Label绘制函数,root参数为根窗体对象,即在root窗体上绘制label控件
label['text']='welcome to the first GUI program using python!'  #设置text属性,即显示内容
label['font']=14            #设置font属性,包括字体大小、字体类型等
lable['fg']='red'           #设置fg前景颜色,这里就是字体颜色
label.pack()                #使用pack方法实现空间的自动布局

root.mainloop()             #窗体消息循环,运行窗体对象


上述代码中使用Label函数绘制了一个标签,设置了标签的显示内容和字体大小。该标签是依附于root窗体中的,所以Label函数里窗体对象为root。标签内容显示使用其text属性key配置,字体大小使用font属性。创建了标签,还需要设置其显示的位置。这里先使用pack方法来实现空间的默认自动布局。运行该代码后,可以看到创建的标签自动居中显示:


python 窗口模块 python窗体模块_java中frame窗体星星坠落_06


绘制Button按钮控件: Button(root)

接下来采用相同的结构来创建一个按钮,按钮是使用频率最高的控件类型。有了按钮,就可以设置当点击按钮时将会执行的事件,也即响应事件。

对于按钮,其基本属性包括:

text--按钮显示文本;command--点击响应事件 ; fg-- 前景字体颜色 ; bg--背景颜色

如下代码:


from tkinter import *
root=Tk()
root.wm_title('hello,python')
root.geometry('300x200')

#在窗体root上添加label标签
label=Label(root)   
label['text']='welcome to the first GUI program using python!'
label['font']=14    #标签字体大小
label['fg']='red'    #标签文本颜色为红色
label.pack()        #标签pack方法布局

#在窗体root上添加Button按钮,同时给定点击事件函数
def callback():     #定义回调函数,当点击按钮时,设置标签对象的文本颜色为蓝色
    label['fg']='blue'  #将label标签对象的文本设置为蓝色
    
btn=Button(root)        #在root窗体上绘制一个Button按钮对象
btn['text']='点击我,标签字体颜色将变成蓝色哦'     #按钮上的文本内容
btn['font']=14          #设置文本大小为14号字体
btn['fg']='white'       #设置fg属性,按钮文本颜色为白色
btn['bg']='blue'        #设置bg属性,按钮背景颜色为蓝色
btn['command']=callback #定义点击按钮时响应事件为callback函数
btn.pack()              #设置按钮对象在窗体上的位置

root.mainloop()         #运行窗体对象


代码中注解的还是比较详细,在按钮这块我们分了两部分:第一块为定义的按钮点击回调函数,也就是响应事件,使用command属性配置;第二块为绘制按钮及其布局,这里依然使用pack方法布局。注意的是按钮的回调函数需要写在绘制按钮代码块之前。后面我们将采用类的写法,可以将绘制和回调函数封装起来。执行上述代码,效果如下:


python 窗口模块 python窗体模块_java中frame窗体星星坠落_07


绘制文本框Entry: Entry(root)

上面介绍了绘制标签和按钮的基本方法,接下来我们换个例子引入文本输入框Entry对象控件。在许多软件或者app当访问时都需要用户注册或登录,其中控件类型就包括标签、输入框和按钮。基本布局如下:


python 窗口模块 python窗体模块_python 窗口模块_08


如果要实现上述窗体设计,需要两个标签、两个文本输入框和两个按钮。

在tkinter中,输入框绘制采用Entry方法,将其依附于root窗体对象,即Entry(root)绘制一个输入框对象,所以使用: entry1= Entry(root) 生成输入框对象entry1,然后再配置entry1的必要属性,最后再进行entry1的布局。

对于输入框而言,输入文本内容后如何取得其中的值肯定是必须考虑的。tkinter中我们可以直接使用输入框对象entry1的get方法获得,即: input_str=entry1.get()。如果想清除文本框的输入,可以使用entry1对象的delete方法,使用格式为: entry1.delete(0,n),式中的n为结束的字符位置,0为输入框中的起始字符。如果要全部清除,直接将n替换为END即可。即:entry1.delete(0,END), 为整个清除。

由于需要多个控件合理并排排列,因此这里选用了另外一种布局方式,就是grid方法,见名知意,grid就是网格。网格就会使用行和列来布局,在使用时就必须给定行和列的位置,即:grid(row=m,column=n),这里的m和n为单元格所在的行和列的位置。tkinter会自动根据当前窗体大小,依据设定的行和列总数将窗体分割为设定的网格,然后依据网格控件的布局来完成内容和组件的显示。

结合前面介绍的绘制标签和绘制按钮的方法,我们可以先采用顺序方式组织代码完成这个登录界面的开发:


from tkinter import *
root=Tk()

#1.绘制两个标签说明及两个文本输入框
#采用grid布局,可以使标签与文本输入框并排显示,
#row=0,column=0,表示第一行第一格,这里放置第一个用户名标签
#row=0,column=1,表示第一行第二格,这里放置第一个文本输入框
#row=1,column=0,表示第二行第一格,这里放置第二个用户密码标签
#row=1,column=1,表示第二行第二格,这里放置第二个文本输入框
label=Label(root)
label['text']='用户名'
label['font']=14
label.grid(row=0,column=0)  
entry_name=Entry(root)      #Entry为输入框控件绘制方法,在root窗体上绘制
entry_name.grid(row=0,column=1)
label=Label(root)
label['text']='用户密码'
label['font']=14
label.grid(row=1,column=0) 
entry_pwd=Entry(root)       #Entry为输入框控件绘制方法,在root窗体上绘制
entry_pwd.grid(row=1,column=1)

#定义点击按钮响应函数
def toLogin():               #点击登录按钮时的响应事件
    name=entry_name.get()    #获取用户名右侧文本输入框的输入值,采用get方法
    pwd=entry_pwd.get()      #获取用户密码右侧文本输入框的输入值,采用get方法
    if name=='admin' and pwd=='admin':    #用户名和密码验证
        print('welcome to my app, dear'+name)
    else:
        print('your information is error!')
def toReset():              #点击重置按钮时的响应事件
    entry_name.delete(0,END)  #清空输入框内容使用delete方法,参数为0,END,表示整个输入框都清空
    entry_pwd.delete(0,END)    #清空密码输入框内容
    
#绘制点击登录和重置按钮
btn_log=Button(root)
btn_log['text']='登录'
btn_log['font']=14
btn_log['fg']='yellow'
btn_log['bg']='green'
btn_log['padx']=15
btn_log['command']=toLogin     #登录按钮的响应函数为toLogin
btn_log.grid(row=2,column=0)   #表示第三行第一格,这里放置第1个登录按钮
btn_reset=Button(root)
btn_reset['text']='重填'
btn_reset['font']=14
btn_reset['padx']=15
btn_reset['fg']='white'
btn_reset['bg']='green'
btn_reset['command']=toReset    #重置按钮的响应函数为toReset
btn_reset.grid(row=2,column=1)  #表示第三行第二格,这里放置第2个重填按钮

root.mainloop()     #运行窗体对象


执行上述代码,可以获得如下效果:


python 窗口模块 python窗体模块_python_09


这个效果没有设计图那样美观,但基本实现了当初的设计布局。但我们再回过去看上述实现代码时按顺序组织下来会觉得比较混乱,案例中还只是非常简单控件组合,如果有更多的控件,这样组织代码肯定不容易理解。因此还需要使用类的编写方法将代码进行封装,便于阅读和理解。上述案例代码可以改写如下:


# -*- coding: utf-8 -*-
"""
Created on Sat Nov 23 19:57:56 2019

@author: caojianhua
"""

from tkinter import *
class myWindow():
    #定义构造函数,绘制窗体及控件
    def __init__(self,master=None):
        self.master=master
        self.master.wm_title('hello,python')
        self.master.geometry('300x200')        
        self.createWidgets()  
        
    #定义绘制控件函数
    def createWidgets(self): 
        label=Label(self.master)
        label['text']='用户名'
        label['font']=14
        label.grid(row=0,column=0)
        entry_name=Entry(self.master)
        entry_name.grid(row=0,column=1)
        label=Label(self.master)
        label['text']='用户密码'
        label['font']=14
        label.grid(row=1,column=0) 
        entry_pwd=Entry(self.master)
        entry_pwd.grid(row=1,column=1)        
        btn_log=Button(self.master)
        btn_log['text']='登录'
        btn_log['font']=14
        btn_log['fg']='yellow'
        btn_log['bg']='green'
        btn_log['padx']=15
        btn_log['command']=self.toLogin
        btn_log.grid(row=2,column=0)
        btn_reset=Button(self.master)
        btn_reset['text']='重填'
        btn_reset['font']=14
        btn_reset['padx']=15
        btn_reset['fg']='white'
        btn_reset['bg']='green'
        btn_reset['command']=self.toReset
        btn_reset.grid(row=2,column=1)
        
    #定义点击按钮回调函数  
    def toLogin(self):
        name=entry_name.get()    #获取文本输入框的get方法
        pwd=entry_pwd.get()
        if name=='admin' and pwd=='admin':
            print('welcome to my app, dear'+name)
        else:
            print('your information is error!')
    def toReset(self):
        entry_name.delete(0,END)  #清空输入框内容使用delete方法
        entry_pwd.delete(0,END)

#实例化一个窗体及控件组合      
root=Tk()      
UserLogWindow=myWindow(root)
root.mainloop()


选择框在窗体设计中也很常见,选择框类型包括单选、多选和列表选择。选择框是给定选项值,选中时获取选项的值为后续操作做准备。这三种类型基本处理方法一样,所以放在一起来进行实践体验。

绘制单选框Radiobutton

Radiobutton单选框:与普通按钮不同,单选框需要在选择后直接获取设置的内容选项,如点击A选择,就获得A选项的值,不过也有其他类型的触发响应。其创建方法与前述控件思路一致,使用Radiobutton函数,将单选框依附于窗体即可,如下:


radioChoice=Radiobutton(rootWindow)
radioChoce.pack()


然后其属性包括text--选项显示内容,value -- 选项自带的值,variable -- 选项变量参数,command -- 选中时响应事件。其中variable参数较为特殊,可以在外部设定值与其关联,然后在响应事件中通过该参数获取单选按钮的value值。

variable主要用于传参和绑定变量。主要参数有:variable, textvariable, onvalue, offvalue, value。他是双向绑定的,也就是说如果该变量发生变化,随之绑定的控件也会变化,与他保持一致。常用的variable变量有:


x = StringVar()  保存一个 string 类型变量, 默认值为""
 x = IntVar()  保存一个整型变量, 默认值为0
 x = DoubleVar()  保存一个浮点型变量,默认值为0.0
 x = BooleanVar()  保存一个布尔型变量,返回值为0表示假,1表示真


操作时主要包括两种:


设置他的值,用set()方法,即:x.set()
  得到他的值,用get()方法,即:x.get()


下面通过代码实践来理解:


from tkinter import *
root=Tk()
root.geometry('300x400')
root.wm_title('hello,python')

label=Label(root,text='下列哪门编程语言是你最喜欢的?请选择:')
label.pack()

#准备好单选选择项,一般使用列表来设置
choiceList=[('python','A'),('C++','B'),('VB','C'),('GO','D')]
#使用tkinter中的StringVar类设定选项所在的值,将其与单选框中的variable绑定关联,当选择某一项时,
#可以使用get方法来获得该项的value值。
v=StringVar()    #观察在单选按钮属性中variable属性值也为v,这两者进行关联绑定
v.set('A')       #将单选按钮默认选择value为A的项,这里为第一项
#定义单选按钮回调函数
def callback():
    choice=v.get()                            #获得选择项中的value值
    label1['text']="您的选项为:  " + choice   #将label1的text属性设置为选项的值
    label1['fg']='red'                        #设置label1的文本颜色为红色
    
#采用循环来设定单选按钮
for item,value in choiceList:              
    radioChoice=Radiobutton(root)
    radioChoice['text']=item           #设定单选按钮后面的内容
    radioChoice['variable']=v          #设定单选按钮变量v
    radioChoice['value']=value         #设定单选按钮自带的值
    radioChoice['command']=callback    #设定单选按钮回调函数
    radioChoice.pack()                 #采用pack方法布局

#绘制一个标签用于显示选中的项
label1=Label(root)              
label1['text']="您的选项为:  " 
label1.pack()

root.mainloop()  #窗体消息循环


当运行代码时效果如图:


python 窗口模块 python窗体模块_java中frame窗体星星坠落_10


绘制多选框Checkbutton

复选框绘制方法与单选框思路是一样的,即使用Checkbutton类:

checkbox=Checkbutton(rootWindow)

其属性设置与单选框也基本类似,不过此时复选框里的variable参数需要各个选项不一致,也就是单独设置variable,比较麻烦。

如下实践代码:


from tkinter import *
root=Tk()
root.geometry('300x400')
root.wm_title('hello,python')

label=Label(root,text='下列哪几门编程语言是你最喜欢的?请选择:')
label.pack()

#准备好多项选择项,使用列表来设置
choiceList=[('python','A'),('C++','B'),('VB','C'),('GO','D')]
#使用tkinter中的BooleanVar类设定选项所在的值,将其与复选框中的variable绑定关联,当选择某一项时,
#可以使用get方法来获得该项的value值。这里由于每一项都有选与不选两种状态,因此如果要获得状态值,
#需要对每一个选项单独设置variable值,如下v0,v1,v2,v3等:
v0=BooleanVar()
v1=BooleanVar()
v2=BooleanVar()
v3=BooleanVar()
def callback():
    choice=''
    if v0.get()==True:
        choice+=choiceList[0][1]
    if v1.get()==True:
        choice+=choiceList[1][1]
    if v2.get()==True:
        choice+=choiceList[2][1]
    if v3.get()==True:
        choice+=choiceList[3][1]
    label1['text']=choice
    label1['fg']='red'
    
#多项选择创建及布局
choice1=Checkbutton(root,text=choiceList[0][0],variable=v0,command=callback)
choice2=Checkbutton(root,text=choiceList[1][0],variable=v1,command=callback)
choice3=Checkbutton(root,text=choiceList[2][0],variable=v2,command=callback)
choice4=Checkbutton(root,text=choiceList[3][0],variable=v3,command=callback)
choice1.pack()
choice2.pack()
choice3.pack()
choice4.pack()

#显示选中内容
label1=Label(root)
label1.pack()

root.mainloop()


运行后效果如图:


python 窗口模块 python窗体模块_输入框_11


列表选择框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()


执行后效果如图:


python 窗口模块 python窗体模块_控件_12


组合选择框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()


执行后效果如图:


python 窗口模块 python窗体模块_控件_13


(3)菜单类控件设计

通常对于一个窗体应用程序而言,菜单是非常重要的构成部分。通过选择菜单,来完成对应的操作。因此在开发这类窗体时,主要关心菜单及其子菜单如何生成、菜单的点击事件响应。至于菜单的布局,默认会放在窗体的顶端,不过也可以通过后续布局来修改。例如python自带的IDLE:


python 窗口模块 python窗体模块_输入框_14


主菜单创建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()


执行后效果如下:


python 窗口模块 python窗体模块_python 窗口模块_15


效果与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主菜单添加了子菜单,同时给每个子菜单添加了点击事件响应,效果如下:


python 窗口模块 python窗体模块_输入框_16


如果要完成类似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()


再来运行,效果如图:


python 窗口模块 python窗体模块_python_17


(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)


运行后效果如图:


python 窗口模块 python窗体模块_python_18


我在上述案例中布局顺序为:先布局一个标签,内容为“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


执行代码,效果如图:


python 窗口模块 python窗体模块_python 窗口模块_19


当点击动画示例时,可以得到如下效果:


python 窗口模块 python窗体模块_python_20

https://www.zhihu.com/video/1182073111012433920


由此可以使用tkinter及画布组合来设计很多好玩的小游戏呢。

至此本文就tkinter的窗体设计开发方面进行了主要功能的介绍,还有一些如开篇介绍的颜色选择器、文件选择器、ttk、tix等模块都未涉及,后续再进行爬虫软件开发时再来详细介绍,有兴趣的同学也可以自行查询tkinter文档来实际体验。