Tkinter布局管理

我们在前面的几节中介绍了Tkinter的几种控件类型,比如标签按钮,下拉条等。在介绍这些控件的同时,也多少的提到了如果在程序窗口中来布局这些小控件,这也是你将要在这一节里所学到的重点-Tkinter的布局管理方法。

Tkinter有三种布局方法,packgrid以及place方法。我们会对它们一一进行介绍。

Tkinter pack布局方法

pack按照字面理解,就是打包的意思,它将刚创建的控件通过打包的方法来放置到窗口中。我们在Tkinter标签的学习章节中,第一次使用这种布局方法,并且列出了pack的所有选项。

我们通过几个例子来看我们如何通过pack以及它的选项来布局Tkinter的控件。

Tkinter pack布局-相对位置

Tkinter Geometry_Pack_Relative Position.py
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()

程序运行后,你得到的是这样的一个窗口界面。

Tkinter pack布局方法的side相对位置

可以看到,按钮buttonWest紧贴着窗口左侧,按钮buttonEast紧贴着窗口右侧。你可以试着缩放下窗口的大小,你会发现,它们仍然会紧贴在窗口两侧,相对位置不会改变。

buttonW.pack(side='left')

side有四个选项,topbottomleftright。它会将控件放在窗口的side侧。就像所举的例子中,buttonW放在窗口的左侧,因为side='left',而buttonE放在窗口的右侧,因为其side=right

现在问题来了,如果两个控件,它们具有相同的side属性,那它们又是怎么布局的呢?

试着自己回答吧,或者运行下以下的代码来实际操作下。

Tkinter Geometry_Pack_Relative Position Two side.py
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,使得控件之间以及控件文字跟控件边界间不是那么的拥挤。这时候,你需要ipadxipady以及ipadxipadx选项的配置。

Tkinter Geometry_Pack_Padding.py
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()

Tkinter pack布局方法增加控件padding

两个按钮都增加了内部20个单位和外部30个单位的x方向上的padding,这里ipadpad的单位是像素,而不是一个字符的宽度。

Tkinter pack布局在x,y方向上的填充

下面的代码实现的功能就是控件的尺寸能够自动的填充至同窗口等宽或者等高,而且当你缩放窗口的时候,控件的尺寸也能够自动随着窗口的大小而变化。

Tkinter Geometry_Pack_Fill.py
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()

Tkinter pack布局方法在X,Y方向上填充

butonX.pack(fill='x')意味着控件buttonX的宽度会填充满整个窗口的宽度,同样的,如果fill='y'就将控件的高度延伸至填满整个窗口的高度,fill='both'就是在X和Y方向的结合,会自动在宽度和高度方向上填满整个窗口。

Tkinter pack布局expand选项-自动展开控件

上面fill=选项是如果将窗口拖放时候,自动将控件在xy方向上填充。跟它类似的一个需求就是假如一个控件有很多的内容,比如说一个列表项,如果把它的内容自动全部展示出来呢?

Tkinter Geometry_Pack_Expand.py
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()

Tkinter pack布局方法在expand选项开启

expand=True or 1时,列表框就会铺开列表中所有的元素,比如例子中,显示了从JanuaryDecember

假如expand选项没有选中的话,那么列表框就默认的只显示了前十个元素,后续的元素需要你选中列表框后通过鼠标或者方向键移动才能够显示出来。

listboxA.pack(fill='both', expand=0)

通过expand=0禁止了列表框自动的铺开所有元素。

Tkinter pack布局方法在expand选项关闭禁止

Tkinter grid布局方法

Tkinter grid是另外一种,也是最重要的一种窗口内控件布局的方法,假如要在三种布局方法里面只学习一种的话,那非grid方法莫属。

grid经常用在用在对话框中,你可以按照网格的坐标位置来安放控件,这样能够得到稳定的控件相对位置。

同以上的举例方法不一样,我们下面的例子会创建一个相对复杂的界面,尽可能的能够用到所有的grid选项,然后在后续的说明中再详细的进行解释。

Tkinter Geometry_Grid_Basic.py
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布局方法

Tkinter grid columnrow选项

labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W+tk.N)

在网格布局中,每一个控件都要放在固定的单元格中,每个单元格的坐标由行列也就是columnrow来确定。

labelWidth控件就放在坐标为(0, 0)的单元格中,坐标是以窗口的左上角为坐标系的原点。

ipadxipadypadx以及pady同前面介绍的pack布局方法中的同名选项意义是一样的,是控件在内部和外部的填充间距。

Tkinter grid sticky选项

sticky的作用是当所产生的单元格大小比控件本身要大的时候,如何进行扩展。

sticky选项 意义
W 左对齐
E 右对齐
N 上对齐
S 下对齐

sticky的默认选项是居中,也就是W+E+N+S

Tkinter columnspanrowspan选项

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个单元格的大小。clonmspan=2rowspan=2就是表示控件以所设定的坐标为起点,在XY方向上都有两个单元格大小的跨度。

Tkinter place方法

Tkinter place是将控件安放在窗口中的固定或者相对的位置上。我们还是同样的采用刚才类似的思路,先列出例子和图形界面来,然后再来解释具体的选项。

Tkinter Geometry_Place_Basic.py
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 Place布局方法

Tkinter place绝对位置

labelA.place(x=0, y=0)
labelB.place(x=20, y=20)

placex=y=选项确定了控件的绝对位置,它们的单位是像素。比如lableB.place(x=20, y=20)的意思就是将控件放置在坐标为(20, 20)的位置上。

Tkinter place相对位置

绝对位置的弊端即使假如当窗口缩放的时候,假如窗口中还有其他的控件是用相对位置来布局的,那么使用绝对位置布局的控件和其他的控件可能就会有重叠,这是你不希望看到的。

place方法中,也有相对位置的方法,这就是

labelD.place(relx=0.5, rely=0.5)

其中,relxrely 的数值是0.0~1.0。它们代表了控件位置和窗口大小的相对大小关系。

比如relx=0.5, rely=0.5的意思即使控件位置就在窗口水平尺寸的一半,也在窗口垂直尺寸的一半。

relx=1.0的位置是窗口的右边框,rely=1.0的位置是窗口的下边框。