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的位置是視窗的下邊框。