How to Build User Interfaces with Python — Tkinter Layouts
This story follows the User Interfaces series. If you have missed the first Tkinter story, you can find it here:
Layouts are very important when building UI because they allow you to display the elements as you want, in a structured way. You can specify the positions of widgets inside a top-level or parent window.
Tkinter provides 3 layout managers, we’ll discover each of them.
The base code for this story will be:
import tkinter as tk
main_window = tk.Tk()
main_window.title("Layouts")
main_window.geometry("400x400")
label1 = tk.Label(main_window, text="Label 1", bg="red")
label2 = tk.Label(main_window, text="Label 2", bg="green")...main_window.mainloop()pack
It’s the first layout manager we have discovered in Tkinter (if you have followed my series). In the first story, we used pack without parameters. But we can customize our widgets by providing some parameters to pack .
Let’s begin with the padding parameters. Padding is used to create space between the widget and its border. There are two parameters:
- ipadx: horizontal padding.
- ipady: vertical padding.
For example:
label1.pack(ipadx=10, ipady=10)
label2.pack(ipadx=20, ipady=20)It will show as:

Then, we have the fill parameter. It allows your widget to fill available space along the x-axis, y-axis, or both. The respecting values to pass to the parameter are x , y and both .
For example:
label1.pack(fill='x')
label2.pack(fill='y')
Why is my second label not filling the whole vertical space?
Widgets don’t have all the vertical space allowed by default. But they have all the horizontal distance, that’s why fill='x' works well.
To change this behavior, you have to provide another argument: expand=True .

label1.pack(fill='x')
label2.pack(fill='y', expand=True)expand=True allows your widget to take all the available space. You can use it without using fill , it will still take up all the available space.
If you use expand for both widgets, they will be allocated the space evenly:
label1.pack(expand=True)
label2.pack(expand=True)Then, we have the side parameter. It allows you to specify the alignment of your widgets. You can use it with left , right , top , and bottom .
label1.pack(expand=True, side='left')
label2.pack(expand=True, side='left')To conclude about pack , it’s useful when you want to display your widgets in a top-down layout or side by side.
grid
This layout manager allows you to organize your widgets in a grid.
You can configure indexes and weights of columns or rows. Weights are used to make columns or rows wider or not.
container.columnconfigure(index, weight)
container.rowconfigure(index, weight)Then, you can position your widgets in a grid. You just have to call the grid method and provide the indexes.
label1.grid(row=0, column=0)
label2.grid(row=0, column=1)If you want to make a widget span, you can do it using the parameters:
label1.grid(row=0, column=0, columnspan=2)
label2.grid(row=1, column=0)
label3.grid(row=1, column=1)
As you can see, “Label 1” spans along a second cell. Currently, it is centered, if you want it to not be centered and for example be aligned to the right, you can use the sticky parameter:
label1.grid(row=0, column=0, columnspan=2, sticky="e")
label2.grid(row=1, column=0)
label3.grid(row=1, column=1)The sticky value is the direction in which the widget will stick (“e” for east, “w” for east, “nw” for northwest, etc…).
You can also provide combinations of directions to make the widget fill the space. For example, sticky="ew" will make the widget fill the cells of the grid from “east” to “west”. You have to combine this with columnspan or rowspan to be sure the widget expands.
In addition, you can also add padding to your widgets. Either external padding, or internal padding.
label1.grid(row=0, column=0, columnspan=2, padx=50, ipady=10)
label2.grid(row=1, column=0)
label3.grid(row=1, column=1)
place
This is the last layout manager. You won’t use it often. It is useful when you want to place widgets at precise positions. Let’s look at an example to see how it works:
label1.place(x=10, y=10, width=100, height=100)
label2.place(x=150, y=10, width=100, height=100)
label3.place(relx=0.5, rely=0.5, anchor="center", width=100, height=100)So, the parameters we can use with place are:
- x/y: absolute position of the widget.
- width/height: dimensions of the widget.
- relx/rely: relative position of the widget.
- anchor: reference used in the coordinates to place the widget. If
anchor="center", the reference used will be the center of the widget, so ifx=10andy=10, it’s the center of the widget which will be placed at these coordinates. Ifanchor="nw", it will be the top-left corner, etc…
So, the code above will display:

This layout manager is useful when you want your application to allow users to place widgets where they want on the screen. For example, it can be used in a drawing application.
A Little Exercise
To be sure you’ve understood, you can try to reproduce the window below:

If you don’t succeed, you will find the correction of this on the repository of the project at this link in LoginFormApp.py . You will also see I used Tkinter enumerations and an object-oriented approach.
Final Note
If you don’t want to miss the other stories of this series, be sure to follow me.
You can also check this: Build User Interfaces with Python, to find other stories about User Interfaces in Python.
You can find the other stories of this series here:
To explore more of my Python stories, click here!
If you liked the story, don’t forget to clap and maybe follow me if you want to explore more of my content :)
You can also subscribe to me via email to be notified every time I publish a new story, just click here!
If you’re not subscribed to medium yet and wish to support me or get access to all my stories, you can use my link:





