Background
When we build applications with graphical user interfaces that are comprised of many widgets — many buttons, text entry fields, canvases, menus, etc. — one of the problems we face is the problem of layout, which is fundamentally the problem of deciding where the various widgets will appear within their window. Tkinter provides tools called layout managers that solve this problem in a few common ways, along with ways to create one's own layout manager if the built-in tools don't do exactly what you need.
Of the built-in layout managers included in Tkinter, the most flexible is one called grid, which should address most straightforward GUI layout needs. This code example focuses on the details of how grid works.
The grid layout manager
The grid layout manager arranges widgets by placing each one into one or more cells on an invisible grid. The grid cells themselves are arranged by the layout manager into rows and columns, with the widgets then arranged within the cells. When you create a GUI using the grid layout manager, you specify which widgets will appear in which cells, as well as the rules dictating how the cells' sizes change as the window's size changes, and how the widgets' sizes and positions change as the grid cells' sizes change.
There are a few things to know about a grid-based layout.
- All of the cells in a particular row have the same height, and all of the cells in a particular column have the same width.
- The heights of different rows and the widths of different columns may be different.
- Initially, the heights of the rows and the widths of the columns are determined by the initial sizes of the widgets they contain.
- As the window's size grows, the additional space is allocated to the heights of the rows and the widths of the columns according to the weights specified on each. Weights are a relative measure, rather than an absolute one. For example, the proportion of a window's additional height allocated to the height of a row is the weight of that row divided by the total weight of all rows. So, for example, if row 0 has weight 1 and row 1 has weight 3, every time the window's height grows by four pixels, one of the pixels is given to row 0 and three are given to row 1. Columns are handled similarly.
- Widgets are arranged within grid cells based on an option called sticky. If a widget is placed into a particular grid cell, the sticky value for a widget specifies which sides of the cell it "sticks" to. The sticky value is specified by adding together the directions "north", "south", "east", and "west".
- By default, widgets float in the center of their cells.
- If a widget is specified to stick to one side of a cell but not the opposing side (e.g., west but not east), it will be moved to the specified edge of the cell.
- If a widget sticks to two opposite sides of a cell, its size will be stretched accordingly. So, for example, if a button sticks to the west and east sides of a cell, it will be stretched horizontally to fill the horizontal area of the cell.
- A widget can be made to fill an entire grid cell by sticking to all four sides (i.e., "north", "south", "east", and "west").
- Padding can be specified, which is empty horizontal and/or vertical space that will be preserved along the outer edge of a grid cell. Horizontal padding is specified using an option called padx, and vertical padding using pady.
- A widget can span more than one row and/or more than one column, by setting the rowspan and/or columnspan options. For example, if a widget is specified to be in row 5 and column 4 with rowspan 3 and columnspan 2, it will span three rows starting from row 5 (i.e., rows 5, 6, and 7) and two columns starting from column 4 (i.e., columns 4 and 5).
- A grid layout can be applied to the entire contents of a window; it can also be applied to the contents of a Frame widget, a widget whose job is to contain other widgets. This allows the entire contents of a window to be laid out in one way, but the widgets in a smaller area of the window to be laid out differently.
A more complex example
In this example, we highlight an example GUI that demonstrates how to control the layout of widgets using Tkinter's grid layout. The image below shows what the GUI looked like when we were done, with yellow gridlines drawn over the GUI so you can see where each grid cell ends and the next one begins.
A few things are evident from the example:
- The grid cells are often a lot larger than the widgets that occupy them. The relationship between the size of a widget and the size of the grid cell it occupies is largely controlled by the sticky option. For example, Button 1 is centered vertically along the left edge of its grid cell because its sticky option has the value tkinter.W (west), while Button 2 rides along the lower right corner of its grid cell because its sticky option is tkinter.S + tkinter.E (southeast).
- The dark red Canvas widget spans two columns, so that it will lie below both buttons. (There would have been other ways to accomplish this, such as using a Frame widget to lay out Button 1 and Button 2.)
- The five buttons along the right-hand edge of the window don't seem to follow the same layout rules as the other widgets in the window. This is because they are placed into a separate Frame widget with its own separate grid layout. The Frame widget spans two rows of the window's grid.