Tkinter 教程 布局管理
我们在前面的几节中介绍了 Tkinter 的几种控件类型,比如标签,按钮,下拉条等。在介绍这些控件的同时,也多少的提到了如果在程序窗口中来布局这些小控件,这也是你将要在这一节里所学到的重点-Tkinter 的布局管理方法。
Tkinter 有三种布局方法,pack
,grid
以及 place
方法。我们会对它们一一进行介绍。
Tkinter pack 布局方法
pack
按照字面理解,就是打包的意思,它将刚创建的控件通过打包的方法来放置到窗口中。我们在 Tkinter 标签的学习章节中,第一次使用这种布局方法,并且列出了 pack 的所有选项。
我们通过几个例子来看我们如何通过 pack
以及它的选项来布局 Tkinter 的控件。
Tkinter pack 布局-相对位置
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side='left')
buttonE = tk.Button(app, text="East", width=15)
buttonE.pack(side='right')
app.mainloop()
程序运行后,你得到的是这样的一个窗口界面。
可以看到,按钮 buttonWest
紧贴着窗口左侧,按钮 buttonEast
紧贴着窗口右侧。你可以试着缩放下窗口的大小,你会发现,它们仍然会紧贴在窗口两侧,相对位置不会改变。
buttonW.pack(side='left')
side 有四个选项,top ,bottom ,left 和 right 。它会将控件放在窗口的 side 侧。就像所举的例子中,buttonW 放在窗口的左侧,因为 side='left'
,而 buttonE 放在窗口的右侧,因为其 side=right
。
现在问题来了,如果两个控件,它们具有相同的 side
属性,那它们又是怎么布局的呢?
试着自己回答吧,或者运行下以下的代码来实际操作下。
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side='left')
buttonE1 = tk.Button(app, text="East 1", width=15)
buttonE1.pack(side='right')
buttonE2 = tk.Button(app, text="East 2", width=15)
buttonE2.pack(side='right')
app.mainloop()
Tkinter pack 增加控件内部外部 padding
有些情况下,你需要在控件的内部或者外部增加一些 padding
,使得控件之间以及控件文字跟控件边界间不是那么的拥挤。这时候,你需要 ipadx,ipady 以及 ipadx,ipadx 选项的配置。
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonW = tk.Button(app, text="West")
buttonW.pack(side='left', ipadx=20, padx=30)
buttonE = tk.Button(app, text="East")
buttonE.pack(side='right', ipadx=20, padx=30)
app.mainloop()
两个按钮都增加了内部 20 个单位和外部 30 个单位的 x 方向上的 padding,这里 ipad 和 pad 的单位是像素,而不是一个字符的宽度。
Tkinter pack 布局在 x,y 方向上的填充
下面的代码实现的功能就是控件的尺寸能够自动的填充至同窗口等宽或者等高,而且当你缩放窗口的时候,控件的尺寸也能够自动随着窗口的大小而变化。
import tkinter as tk
app = tk.Tk()
app.geometry('300x200')
buttonX = tk.Button(app, text="Fill X", bg="red", height=5)
buttonX.pack(fill='x')
buttonY = tk.Button(app, text="Fill Y", bg="green", width=10)
buttonY.pack(side='left', fill='y')
app.mainloop()
butonX.pack(fill='x')
意味着控件 buttonX 的宽度会填充满整个窗口的宽度,同样的,如果 fill='y'
就将控件的高度延伸至填满整个窗口的高度,fill='both'就是在 X 和 Y 方向的结合,会自动在宽度和高度方向上填满整个窗口。
Tkinter pack 布局 expand 选项-自动展开控件
上面 fill=
选项是如果将窗口拖放时候,自动将控件在 x 和 y 方向上填充。跟它类似的一个需求就是假如一个控件有很多的内容,比如说一个列表项,如果把它的内容自动全部展示出来呢?
import tkinter as tk
import calendar
app = tk.Tk()
buttonX = tk.Button(app, text="Label ", bg="blue", height=5)
buttonX.pack(fill='x')
listboxA = tk.Listbox(app, width=10)
listboxA.pack(fill='both', expand=1)
for i in range(1,13):
listboxA.insert(tk.END, calendar.month_name[i])
app.mainloop()
当 expand=True or 1
时,列表框就会铺开列表中所有的元素,比如例子中,显示了从 January 到 December。
假如 expand
选项没有选中的话,那么列表框就默认的只显示了前十个元素,后续的元素需要你选中列表框后通过鼠标或者方向键移动才能够显示出来。
listboxA.pack(fill='both', expand=0)
通过 expand=0
禁止了列表框自动的铺开所有元素。
Tkinter grid 布局方法
Tkinter grid 是另外一种,也是最重要的一种窗口内控件布局的方法,假如要在三种布局方法里面只学习一种的话,那非 grid
方法莫属。
grid
经常用在用在对话框中,你可以按照网格的坐标位置来安放控件,这样能够得到稳定的控件相对位置。
同以上的举例方法不一样,我们下面的例子会创建一个相对复杂的界面,尽可能的能够用到所有的 grid 选项,然后在后续的说明中再详细的进行解释。
import tkinter as tk
app = tk.Tk()
labelWidth = tk.Label(app,
text = "Width Ratio")
labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W+tk.N)
labelHeight = tk.Label(app,
text = "Height Ratio")
labelHeight.grid(column=0, row=1, ipadx=5, pady=5, sticky=tk.W+tk.S)
entryWidth = tk.Entry(app, width=20)
entryHeight = tk.Entry(app, width=20)
entryWidth.grid(column=1, row=0, padx=10, pady=5, sticky=tk.N)
entryHeight.grid(column=1, row=1, padx=10, pady=5, sticky=tk.S)
resultButton = tk.Button(app, text = 'Get Result')
resultButton.grid(column=0, row=2, pady=10, sticky=tk.W)
logo = tk.PhotoImage(file='python.gif')
labelLogo = tk.Label(app, image=logo)
labelLogo.grid(row=0, column=2, columnspan=2, rowspan=2,
sticky=tk.W+tk.E+tk.N+tk.S, padx=5, pady=5)
app.mainloop()
Tkinter grid column 和 row 选项
labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W+tk.N)
在网格布局中,每一个控件都要放在固定的单元格中,每个单元格的坐标由行列也就是 column 和 row 来确定。
labelWidth
控件就放在坐标为 (0, 0) 的单元格中,坐标是以窗口的左上角为坐标系的原点。
ipadx,ipady,padx 以及 pady 同前面介绍的 pack 布局方法中的同名选项意义是一样的,是控件在内部和外部的填充间距。
Tkinter grid sticky 选项
sticky 的作用是当所产生的单元格大小比控件本身要大的时候,如何进行扩展。
sticky 选项 | 意义 |
---|---|
W | 左对齐 |
E | 右对齐 |
N | 上对齐 |
S | 下对齐 |
sticky
的默认选项是居中,也就是 W+E+N+S
Tkinter columnspan 和 rowspan 选项
labelLogo.grid(row=0, column=2, columnspan=2, rowspan=2,
sticky=tk.W+tk.E+tk.N+tk.S, padx=5, pady=5)
在 logo 控件中,单元格的坐标是 (column=2, row=0)
,又因为 logo 的尺寸比较大,我们让它占据 2x2 个单元格的大小。columnspan=2
和 rowspan=2
就是表示控件以所设定的坐标为起点,在 X 和 Y 方向上都有两个单元格大小的跨度。
Tkinter place 方法
Tkinter place 是将控件安放在窗口中的固定或者相对的位置上。我们还是同样的采用刚才类似的思路,先列出例子和图形界面来,然后再来解释具体的选项。
import tkinter as tk
app = tk.Tk()
app.geometry('300x300')
labelA = tk.Label(app, text = "Label (0, 0)", fg="blue", bg="#FF0")
labelB = tk.Label(app, text = "Label (20, 20)", fg="green", bg="#300")
labelC = tk.Label(app, text = "Label (40, 50)", fg="black", bg="#f03")
labelD = tk.Label(app, text = "Label (0.5, 0.5)", fg="orange", bg="#0ff")
labelA.place(x=0, y=0)
labelB.place(x=20, y=20)
labelC.place(x=40, y=50)
labelD.place(relx=0.5, rely=0.5)
app.mainloop()
Tkinter place 绝对位置
labelA.place(x=0, y=0)
labelB.place(x=20, y=20)
place 中 x=
和 y=
选项确定了控件的绝对位置,它们的单位是像素。比如 lableB.place(x=20, y=20)
的意思就是将控件放置在坐标为 (20, 20) 的位置上。
Tkinter place 相对位置
绝对位置的弊端即使假如当窗口缩放的时候,假如窗口中还有其他的控件是用相对位置来布局的,那么使用绝对位置布局的控件和其他的控件可能就会有重叠,这是你不希望看到的。
在 place 方法中,也有相对位置的方法,这就是
labelD.place(relx=0.5, rely=0.5)
其中,relx 和 rely 的数值是 0.0~1.0。它们代表了控件位置和窗口大小的相对大小关系。
比如 relx=0.5, rely=0.5
的意思即使控件位置就在窗口水平尺寸的一半,也在窗口垂直尺寸的一半。
relx=1.0
的位置是窗口的右边框,rely=1.0
的位置是窗口的下边框。