Tkinter Layout Management

In the previous sections, we have introduced several Tkinter widget types, such as label, button, drop-down menu, etc. Meanwhile, we have also mentioned briefly how to layout these widgets in the program window. This is the key point that you will learn in this section - Tkinter’s geometry management methods.

Tkinter has three geometry management methods, that is, pack, grid, and place. Let’s go through them one by one.

Tkinter pack Layout Method

pack method, as literally indicated, packs the widget to the window frame after it is created. We come across this layout method in the section Tkinter Label where all the pack options are also listed.

We will show you how to layout widgets with pack method (also its options). A few examples help to demonstrate the right configuration.

Tkinter pack Layout - Relative Position

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

Run the program, you will get a window like this,

Tkinter pack layout method-side relative position

As you can seeļ¼ŒbuttonWest snaps to the left side of the window and buttonEast snaps to the right side of the window. You can try to scale the size of the window below, but you will find that they will still cling to the sides of the window and the relative position will not change.

buttonW.pack(side='left')

side has four options -

  1. top
  2. bottom
  3. left
  4. right

It places the widget on the side of the window. As illustrated in the example, buttonW is allocated on the left side of the window, because side='left', while buttonE is on the right side of the window, because side=right.

Now we have an interesting scenario, what happens if two widgets have the same side property, how the layout will be?

Try to answer it yourself, or check it by running the following codes.

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 to add widget internal and external padding

In some cases, you need to add some padding inside or outside the widget so that there is less congestion between the widgets, and also between the widget text and the widget boundaries. Now, you need options as ipadx, ipady, ipadx and ipadx.

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 layout method - increase widget padding

Both buttons add inner 20 units padding and outer 30 units in the x, and the unit is pixel but not the width of one character.

Tkinter pack Layout Filling in x, y direction

The following code implementation could automatically fill the widget dimension to the same width or the same height as the window, and when you zoom the window, the size of the control can automatically change with the size of the window.

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 Layout Method Filling in X,Y Direction

butonX.pack(fill='x') means buttonX will fill the width of the whole window. Similarly, fill='y' will fill the height of the whole window, and meanwhile fill='both' will fill both the width and height.

Tkinter pack Layout Option expand - automatically expand

Above fill= option will automatically fill the widget in x and/or y direction when the window size is modified. Another similar requirement is how to automatically display all the contents if the widget includes multiple options, like a list?

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 layout method enable expand option

When expand=True or 1, the list box will list all the items, from January to December as demonstrated in the above example.

If expand is set to be False, then the list box only shows the first 10 items by default. You need to use the mouse or direction keys to show the hidden items after the list box is selected.

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

expand=0 disables the list box to automatically show all items.

Tkinter pack layout method when expand option is disabled

Tkinter grid Layout Method

Tkinter grid is another and also the most important layout geometry method. This is the one you should learn if you only want to learn one single method among all geometry managers.

grid is often used in dialog boxes, and you could place the widgets based on the position coordinates of the grid. grid layout method could have stable relative positions of all widgets.

The following example will create a relatively complicated GUI compared to the above examples, which uses as many options of grid as possible that will be explained in the next sections.

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 layout method

Tkinter grid column and row options

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

Every widget shall be placed in the absolute cell in the grid layout method. The cell coordinate is determined by column and row.

labelWidth widget is placed in the cell of position (0, 0). The coordinate starts from the upper left corner of the window.

ipadx, ipady, padx and pady options are the same as those in pack method.

Tkinter grid sticky option

sticky determines how the widget sticks to the cell when the widget is smaller than the cell.

sticky Meaning
W stick to left
E stick to right
N stick to top
S stick to bottom

The default sticky option is center, that is W+E+N+S.

Tkinter columnspan and rowspan options

labelLogo.grid(row=0, column=2, columnspan=2, rowspan=2,
               sticky=tk.W+tk.E+tk.N+tk.S, padx=5, pady=5)

The cell coordinate of labelLogo is (column=2, row=0) and the size of logo is relatively large, therefore it is allocated with cell size of 2x2. clonmspan=2 and rowspan=2means the widget has spans of two cells both in X and Y directions starting from the position of the widget.

Tkinter place Method

Tkinter place method places the widget in an absolute or relative position in the window. We still use the same approach as above to introduce the options of this layout method.

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 Layout method

Tkinter place Absolute Position

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

x= and y= options in place determines the absolute positions of the widget, which have the unit as pixel. For example, lableB.place(x=20, y=20) means labelB is placed in the coordinate of (20, 20).

Tkinter place Relative Position

The drawback of the absolute position is that if there are other widgets in the window placed with relative positions, when the window is zoomed, the widget using the absolute position layout will possibly have the overlap with other widgets.

place layout method also has the relative position option, that is,

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

Where relx and rely are in the range of 0.0~1.0. It is the relative percentage of the widget position to the window size.

For example, relx=0.5, rely=0.5 means the widget is placed in the 50% of the window width and 50% of the window height.

relx=1.0 is the right boundary of the window, and rely=1.0 is the bottom boundary of the window.