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