添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
python开发GUI-----tkinter详细教程

python开发GUI-----tkinter详细教程

1. 前言

1.1 总体介绍

tkinter是python内置的包,可以用来开发GUI,但这个包比较简陋,适合个人学习,或者个人开发小型的应用。公司企业用的少。但入门简单,比较方便初学者学习。本文是基于python3.0以上讲解,使用pycharm运行。

1.2 tkinter的"hello world"

from tkinter import *
root = Tk()
root.geometry('300x200')
root.title('my window')
btn = Button(root,text='点击')
btn.pack()
root.mainloop()

#1实例化一个顶级窗口,可以看作是根窗口

#2设置这个窗口的宽和高

#3设置窗口的标题

#4创建一个按钮,按钮名字为”点击“

#5放置按钮(怎么放到根窗口)

#6让根窗口保持运行

2. 约定一些定义

window:创建的一个矩形区域

widget:表示组件,比如按钮,文本框,标签,框架等等

frame:表示框架,相当于一个容器,用来放其他小组件,便于打包处理

child, parent:比如创建了一个框架,在框架上放了一个按钮,那么框架就是按钮的父亲,按钮是框架的孩子。

3. 布局管理

tkinter有多种控件,当你开发GUI时,如何来管理控件和布局界面是个重要的事情。tkinter中最常用的有两种布局方法pack和grid。(下面w表示一个实例化的控件)

3.1 w.pack(options=)

pack组件的设置位置的参数有以下几种:

after:将组件置于其他组件之后;

before:将组件置于其他组件之前;

anchor:组件的对齐方式,默认是CENTER,其他可选择对齐方式如图

expand:标明组件是否充满额外的父空间(如果有的话),取值1或0。默认是0。该参数常与fill同时使用。

fill:设置组件填满所分配容器区间的方式,如果fill=X表示组件可以填满所分配空间的X轴不留空白,如果fill=Y 表示组件可以填满所分配空间的Y轴不留空白。如果是fill=BOTH,X,Y轴同时填满,默认值是NONE。

ipadx:指定组件内容与组件边界的距离

ipady:指定组件内容与组件边界的距离

padx:指定组件与组件的距离

pady:指定组件与组件的距离

side:标明组件如何排列,默认值是TOP,由上往下排列


side用法:

side=TOP,默认值,由上往下排列;BOTTOM,由下往上;LEFT,由左往右;RIGHT,由右往左。注意:谁先调用pack函数谁就先出现。

举例:side=BOTTOM

from tkinter import *
root = Tk()
root.geometry('300x200')
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack(side=BOTTOM)
btn2 = Button(root,text='按钮2',bg='red')
btn2.pack(side=BOTTOM)
root.mainloop()

anchor用法:

from tkinter import *
root = Tk()
root.geometry('300x200')
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack(anchor=NW)
btn2 = Button(root,text='按钮2',bg='red')
btn2.pack(anchor=N)
btn3 = Button(root,text='按钮3',bg='red')
btn3.pack(anchor=NE)
btn4 = Button(root,text='按钮4',bg='red')
btn4.pack()
root.mainloop()

由于side参数默认值TOP,组件从上到下排列,因此这四个按钮先按照从上往下的顺序排放,然后按照anchor参数进行各自方向的对齐。按钮4没有anchor参数,是因为anchor默认值为CENTER。实际是有的。

当没有anchor参数时,如下,此时side默认为TOP,anchor默认CENTER。所以就是从上往下,居中排列。

from tkinter import *
root = Tk()
root.geometry('300x200')
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack()
btn2 = Button(root,text='按钮2',bg='red')
btn2.pack()
btn3 = Button(root,text='按钮3',bg='red')
btn3.pack()
btn4 = Button(root,text='按钮4',bg='red')
btn4.pack()
root.mainloop()

当anchor全取NW时,

from tkinter import *
root = Tk()
root.geometry('300x200')
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack(anchor=NW)
btn2 = Button(root,text='按钮2',bg='red')
btn2.pack(anchor=NW)
btn3 = Button(root,text='按钮3',bg='red')
btn3.pack(anchor=NW)
btn4 = Button(root,text='按钮4',bg='red')
btn4.pack(anchor=NW)
root.mainloop()

fill参数用法:

fill=X,fill=Y,fill=BOTH,三种取值。默认值是NONE 。下面我们通过例子来观察用法,这里我们不在设定窗口大小,他会自动调整大小包裹组件。

from tkinter import *
root = Tk()
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack()
btn2 = Button(root,text='按钮按钮按钮2',bg='red')
btn2.pack()
root.mainloop()

当我们修改代码 btn1.pack() btn1.pack(fill=X) 时,运行结果如下

并且当你把窗口拖拽变大时,你发现 按钮1 在X轴方向随之扩大。如下图。因此说fill=X就是让组件可以填满所分配空间的X轴不留空白。那么同理fill=Y和fill=BOTH分别表示在Y轴不留空白,在X,Y都不留空白。

下面我们看一个现象:

from tkinter import *
root = Tk()
root.title('my window')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack(side=LEFT,fill=Y)
btn2 = Button(root,text='按钮按钮按钮2',bg='red')
btn2.pack(fill=X)
btn3 = Button(root,text='按钮按钮3',bg='red')
btn3.pack(fill=Y)
root.mainloop()

上面的代码表示先从左边放按钮1,并让他填充Y轴分配的空间,然后在右侧从上往下放按钮2和按钮3。现在看上去运行结果好像没问题,但当我们拖拽窗口大小时,出现如下现象:

我们发现按 钮3 没有按照我们想的填充 Y 轴。这是因为当组件从左往右或从右往左放置时,pack管理员分配的空间是 Y 轴空间。而组件从上往下或从下往上放时,分配给组件的空间是X轴空间。打个比方说,给一群学生分配座位,从教室左边开始,学生一列一列的坐,这个时候我并不关心桌子对于学生够不够宽,我只关心这一列座位够不够,能不能把学生放进去。也就是说,从左往右放组件时,系统只给了它Y轴方向扩展的机会,而在X轴默认为组件自身的宽度,保持不变。所以 按钮3 是从上往下放的,只分配了X轴空间,没有分配多余的Y空间。上面的空白处是父容器的空间,并不是分配给 按钮3 的空间。

那么如果想让按钮3填充Y轴怎么办?用expand参数

expand用法:

该参数取值为0,1。用于设定组件是否填满额外的父容器空间。默认是0.

我们把上面的 btn3.pack(fill=Y) 修改为 btn3.pack(fill=Y,expand=1) ,运行结果如下:

原始图片
拖拽后的图片

当我们拖拽窗口变大时,按钮3自动填充Y轴。

ipadx和ipady用法:

用来设置文字和组件边界的距离。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack()
root.mainloop()

修改代码 btn1.pack() btn1.pack(ipadx=30,ipady=20) ,运行如下,文字和按钮边界间距改变了。

padx和pady用法:

用来设置同一个容器中组件与其他组件或者容器边界的距离

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red')
btn1.pack(side=LEFT,anchor=NW)
btn2 = Button(root,text='按钮2',bg='red')
btn2.pack(side=LEFT,anchor=NW,padx=10,pady=10)
root.mainloop()

我们看到按钮2在X方向与其他边界保持了10的距离,在Y方向也与边界保持距离10.如果两个按钮都设置了padx=10,那么在X方向,按钮1与按钮2距离就是20。

after和before用法:

这两个参数基本不用,因为组件出现的顺序可以依靠你调用pack的顺序出现。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red')
btn2 = Button(root,text='按钮2',bg='red')
btn3 = Button(root,text='按钮3',bg='red')
btn1.pack()
btn2.pack()
btn3.pack()
root.mainloop()

如果修改代码

before表示btn2要显示在btn1之前。但要实现这样的目的,你只需要调换btn1.pack()和btn2.pack()顺序即可。因此这两个参数基本不用。

3.2 w.grid(options=)

grid是以网格的方式放组件。有以下几个参数

row和column:表示组件放在哪行哪列的格子里

rowspan和columnspan:用来合并单元格

ipadx和ipady:与3.1节用法相同

padx和pady:与3.1节用法相同

sticky:该功能类似3.1节的anchor,但只能取值N/S/W/E,就是上下左右对齐

row和column用法:

读者可观察代码grid函数,与运行结果对照。比较容易理解。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red')
btn2 = Button(root,text='按钮2',bg='red')
btn3 = Button(root,text='按钮3',bg='red')
btn1.grid(row=0,column=0)
btn2.grid(row=0,column=1)
btn3.grid(row=0,column=2)
btn4 = Button(root,text='按钮4',bg='red')
btn5 = Button(root,text='按钮5',bg='red')
btn6 = Button(root,text='按钮6',bg='red')
btn4.grid(row=1,column=0)
btn5.grid(row=1,column=1)
btn6.grid(row=1,column=2)
root.mainloop()

rowspan和columnspan用法:

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red')
btn2 = Button(root,text='按钮2',bg='red')
btn3 = Button(root,text='按钮3',bg='red')
btn1.grid(row=0,column=0)
btn2.grid(row=0,column=1,rowspan=2)
btn3.grid(row=0,column=2)
btn4 = Button(root,text='按钮4',bg='red')
btn6 = Button(root,text='按钮6',bg='red')
btn4.grid(row=1,column=0)
btn6.grid(row=1,column=2)
root.mainloop()

代码 btn2.grid(row=0,column=1,rowspan=2)中rowspan=2, 是让按钮2从row=0起占用两行。同时原来按钮5那个格子就不能在放组件了,因为它被占用了。columnspan的用法是一样的,表示从组件所在列开始,占用几列。可以一起使用,同时占用行和列。

ipadx和ipady:与3.1节用法相同

padx和pady:与3.1节用法相同

sticky用法:

该功能类似3.1节的anchor,但只能取值N/S/W/E,就是上下左右对齐。如果我们修改 rowspan和columnspan用法这一小节的代码

btn2.grid(row=0,column=1,rowspan=2)

修改为

btn2.grid(row=0,column=1,rowspan=2,sticky=N)

运行结果如下,btn2要上对齐:

如果我们再次修改为

btn2.grid(row=0,column=1,rowspan=2,sticky=N+S)

由于sticky=N+S,表示要上下都对齐,但按钮2又没这么大,所以就被拉长了,实现上下对齐。读者可对N/S/W/E自行尝试组合使用。sticky=N+S+W+E,表示上下左右都要对齐。sticky=N+S+W表示上下对齐,同时左边对齐。

4. 常用的几种组件

组件类(每一个组件其实都是一个class类) 名称 功能
Label 标签 显示文字标签
Button 按钮 显示一个按钮
Entry 单行文本框 可以输入的文本框,比如账号密码
Radiobutton 选项按钮 比如选择性别时,用的单选按钮
Frame 框架 用来装子组件
Scale 尺度条 定义一个滑动条,以帮助用户设置数值
Spinbox 数值输入组件 与Scale类似
Message 显示短消息,与Label类似
Messagebox 对话框 比如软件弹出的窗口,告诉你错误
Listbox 列表框
Scrollbar 滚动条 比如拖动excel表的那个条
OptionMenu 下拉列表
Combobox 组合框
PanedWindow 容器 与Frame类似
Notebook 容器 与Frame类似
Menu 菜单
Toolbars 工具栏 软件上用的那种工具栏功能
Text 文字区域
Treeview 类似表格
Canvas 画布 用来画图形,如线条及多边形等
Checkbutton 复选框 打对勾的那种选项

以上这些组件所具有的共同属性:

fg或foreground:设置前景色彩

bg或background:设置背景色彩

除了用英文表示颜色,还可以用十六进制代码表示,上图截取了一部分作为展示。下面用代码实验。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red',fg='yellow')
btn1.pack()
root.mainloop()

width和height:设置组件的宽度和高度

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red',fg='yellow',width=10,height=2)
btn1.pack()
root.mainloop()

anchor:设置文字在组件内的位置

请注意与第三章布局管理的anchor进行区别,一个是文字在组件内位置,一个是组件在父容器中的位置。两者取值是相同的。但是当你没有设置width或height属性时,由于组件默认大小,因此该参数不会产生什么效果。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮1',bg='red',fg='yellow',
              width=10,height=2,anchor=SE)
btn1.pack()
root.mainloop()

font:设置文字字形

family:选择字型,比如楷书,隶书,新罗马字体

size:字号,参考word

weight:字体粗细,取值bold或normal

slant:字体是否倾斜,取值roman, italic

underline:字体有没有下划线

overstrike:用于指定是否在字体中间绘制一条水平线

必须按顺序放置参数,可以不放全部参数,比如 font=('华文行楷',20,'bold','italic')

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('200x100')
btn1 = Button(root,text='按钮按钮1',
              font=('华文行楷',20,'bold','italic','underline','overstrike'))
btn1.pack()
root.mainloop()

relief:设置组件的边框

可取值为FLAT,RAISED,SUNKEN,GROOVE,RIDGE,SOLID,组件边框效果如下,

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('400x200')
btn = Button(root,text='不设置relief')
btn1 = Button(root,text='FLAT',relief=FLAT)
btn2 = Button(root,text='RAISED',relief=RAISED)
btn3 = Button(root,text='SUNKEN',relief=SUNKEN)
btn4 = Button(root,text='GROOVE',relief=GROOVE)
btn5 = Button(root,text='SOLID',relief=SOLID)
btn6 = Button(root,text='RIDGE',relief=RIDGE)
btn.pack()
btn1.pack(side=LEFT,padx=5)
btn2.pack(side=LEFT)
btn3.pack(side=LEFT,padx=5)
btn4.pack(side=LEFT)
btn5.pack(side=LEFT,padx=5)
btn6.pack(side=LEFT)
root.mainloop()

读者可对比设置relief属性与不设置relief属性时,组件边框变化的情况。

config:设置组件的属性

组件在创建时可以直接设置属性,比如背景颜色,字体大小,如果有部分属性没有建立,未来在程序执行时如果想要建立或是更改属性,可以使用config()方法。传入的参数与初始传入的参数相同。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('100x100')
btn = Button(root,text='按钮')
btn.pack()
btn.config(bg='red')
root.mainloop()

cursor:设置鼠标移动到组件上时的形状

用以下代码演示:当鼠标经过按钮时,变为心型。下图红色圈中的形状。

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('100x100')
btn = Button(root,text='raised',cursor='heart')
btn.pack()
root.mainloop()

5. 标签Label,文本框Entry,按钮Button

语法格式:Label(父对象,options,....),Entry(父对象,options,....)。Button(父对象,options,....)。options代表可选参数,比如背景,组件高度宽度等等。下面先用代码展示一下:

from tkinter import *
root = Tk()
root.title('my window')#设置标题
root.geometry('250x100')#设置窗口大小
lab=Label(root,text='账号')#创建标签
ent=Entry(root)#创建文本框
btn=Button(root,text='提交')
lab.pack(side=LEFT)#两个组件从左往右排列
ent.pack(side=LEFT)
btn.pack(side=LEFT)
root.mainloop()

这就是咱们常用的账号登陆界面。

Label常用属性有:

bg:背景色彩,如bg='red'

bd:标签边界宽度,默认是bd=1

fg:前景色彩

text:标签的内容,比如上面的”账号“

font:字型设置,参见第四章font

textvariable:设置标签以变量的方式显示,该参数相当于把标签的text变成了可变化的,就好比C语言的变量,你可以重新赋值。

Entry常用属性:

bg:背景色彩,如bg='red'

bd:标签边界宽度,默认是bd=1

fg:前景色彩

font:字型设置,参见第四章font

command:当用户更改内容时,会自动执行此函数

state:文本框输入状态,默认NORMAL表示可以输入,DISABLE表示无法输入

textvariable:文字变量

Button常用属性:

bg:背景色彩,如bg='red'

bd:标签边界宽度,默认是bd=1

fg:前景色彩

font:字型设置,参见第四章font

command:当用户点击时,会自动执行此函数

state:默认NORMAL,若设置为DISABLE,按钮显示为灰色,无法点击

text:功能按钮的名称。

下面给一个应用的小例子:

from tkinter import *
#定义一个打印函数
def dayin():
    print(ent1.get())#get函数可以用来获得文本框的内容
    print(ent2.get())
root = Tk()
root.title('my window')#设置标题
root.geometry('250x100')#设置窗口大小
lab1=Label(root,text='账号')#创建账号标签
lab2=Label(root,text='密码')#创建密码标签
ent1=Entry(root)#创建文本框
ent2=Entry(root)#创建文本框
btn=Button(root,text='打印',command=dayin)#把按钮和函数dayin绑定,点击按钮时,执行此函数
lab1.grid(row=0,column=0)
ent1.grid(row=0,column=1)
lab2.grid(row=1,column=0)
ent2.grid(row=1,column=1)
btn.grid(row=2,column=0,columnspan=2)
root.mainloop()


当你在文本框输入内容,并点击打印按钮时,会输出相关的内容,

除了上面用的get方法,文本框还有insert()和delete()方法

insert(index,s),s是要插入的字符串,字符串会插入在index位置

delete(first,last=None),该方法是删除文本框内的从第first字符到last-1字符间的字符,如果删除整个文本框内容可以用delete(0,END)

下面用程序演示:

from tkinter import *
root = Tk()
root.title('my window')#设置标题
root.geometry('250x100')#设置窗口大小
lab1=Label(root,text='账号')#创建账号标签
ent1=Entry(root)#创建文本框
lab1.pack(side=LEFT)
ent1.pack(side=LEFT)
ent1.insert(0,'asdf')#在0位置插入asdf
ent1.insert(1,'123')#在插入asdf的基础上,又在1位置插入123
root.mainloop()

如果加入代码ent1.delete(0,END),那么内容就会被删除。

6. 变量类别

变量可以用来传递数据。变量类型有以下几种:

x=IntVar()#整型变量,默认是0
x=DoubleVar()#浮点型变量,默认是0.0
x=StringVar()#字符串变量,默认是""
x=BooleanVar()#布尔型变量,True是1,False是0

可以用get()和set()方法获取变量,设置变量。下面用代码演示:

from tkinter import *
def shuchu():
    x.set('输入123')#设置变量内容
root = Tk()
root.title('my window')#设置标题
root.geometry('250x100')#设置窗口大小
x=StringVar()#定义变量
ent=Entry(root,textvariable=x)#创建文本框
ent.pack()
btn=Button(root,text='按钮',command=shuchu)
btn.pack()
root.mainloop()

代码逻辑:先定义一个字符变量x,把它和文本框绑定textvariable=x,当我点击按钮时,执行shuchu函数,在函数中我调用了变量的set函数,设置内容。由于是绑定的,我设置内容后,就会显示在文本框中。

点击按钮:

7. 选项按钮和复选框

选项按钮Radiobutton,复选框Checkbutton

先看一下这两个组件样子:

from tkinter import *
root = Tk()
root.title('my window')#设置标题
root.geometry('250x100')#设置窗口大小
r1=Radiobutton(root,text='男')#创建选项按钮
r2=Radiobutton(root,text='女')
r1.pack()