The grid geometry manager is easy to understand and perhaps the most useful geometry manager in Tkinter. The central idea of the grid geometry manager is to organize the container frame into a two-dimensional table that is divided into a number of rows and columns. Each cell in the table can then be targeted to hold a widget. In this context, a cell is an intersection of imaginary rows and columns.
Note that in the grid method, each cell can hold only one widget. However, widgets can be made to span multiple cells.
Within each cell, you can further align the position of the widget using the sticky option. The sticky option decides how the widget is expanded. If its container cell is larger than the size of the widget that it contains, the sticky option can be specified using one or more of the N, S, E, and W options or the NW, NE, SW, and SE options.
Not specifying stickiness defaults stickiness to the center of the widget in the cell.
Let's have a look at demo code that illustrates some features of the grid geometry manager. The code in 1.06.py generates a GUI, as shown in the following screenshot:
The following code (1.06.py) generates the preceding GUI:
import tkinter as tk
root = tk.Tk()
tk.Label(root, text="Username").grid(row=0, sticky=tk.W)
tk.Label(root, text="Password").grid(row=1, sticky=tk.W)
tk.Entry(root).grid(row=0, column=1, sticky=tk.E)
tk.Entry(root).grid(row=1, column=1, sticky=tk.E)
tk.Button(root, text="Login").grid(row=2, column=1, sticky=tk.E)
root.mainloop()
The following is a description of the preceding code:
- Take a look at the grid position defined in terms of the row and column positions for an imaginary grid table spanning the entire frame. See how the use of sticky=tk.W on both the labels makes them stick on the left-hand side, thus resulting in a clean layout.
- The width of each column (or the height of each row) is automatically decided by the height or width of the widgets in the cell. Therefore, you need not worry about specifying the row or column width as equal. You can specify the width for widgets if you need that extra bit of control.
- You can use the sticky=tk.NSEW argument to make the widget expandable and fill the entire cell of the grid.
In a more complex scenario, your widgets may span across multiple cells in the grid. To make a grid to span multiple cells, the grid method offers handy options such as rowspan and columnspan.
Furthermore, you may often need to provide some padding between cells in the grid. The grid manager provides the padx and pady options to provide padding that needs to be placed around a widget.
Similarly, the ipadx and ipady options are used for internal padding. These options add padding within the widget itself. The default value of external and internal padding is 0.
Let's have a look at an example of the grid manager, where we use most of the common arguments to the grid method, such as row, column, padx, pady, rowspan, and columnspan.
1.07.py produces a GUI, as shown in the following screenshot, to demonstrate how to use the grid geometry manager options:
The following code ( 1.07.py ) generates the preceding GUI:
import tkinter as tk
parent = tk.Tk()
parent.title('Find & Replace')
tk.Label(parent, text="Find:").grid(row=0, column=0, sticky='e')
tk.Entry(parent, width=60).grid(row=0, column=1, padx=2, pady=2,
sticky='we', columnspan=9)
tk.Label(parent, text="Replace:").grid(row=1, column=0, sticky='e')
tk.Entry(parent).grid(row=1, column=1, padx=2, pady=2, sticky='we',
columnspan=9)
tk.Button(parent, text="Find").grid( row=0, column=10, sticky='e' + 'w',
padx=2, pady=2)
tk.Button(parent, text="Find All").grid(
row=1, column=10, sticky='e' + 'w', padx=2)
tk.Button(parent, text="Replace").grid(row=2, column=10, sticky='e' +
'w', padx=2)
tk.Button(parent, text="Replace All").grid(
row=3, column=10, sticky='e' + 'w', padx=2)
tk.Checkbutton(parent, text='Match whole word only').grid(
row=2, column=1, columnspan=4, sticky='w')
tk.Checkbutton(parent, text='Match Case').grid(
row=3, column=1, columnspan=4, sticky='w')
tk.Checkbutton(parent, text='Wrap around').grid(
row=4, column=1, columnspan=4, sticky='w')
tk.Label(parent, text="Direction:").grid(row=2, column=6, sticky='w')
tk.Radiobutton(parent, text='Up', value=1).grid(
row=3, column=6, columnspan=6, sticky='w')
tk.Radiobutton(parent, text='Down', value=2).grid(
row=3, column=7, columnspan=2, sticky='e')
parent.mainloop()
Note how just 14 lines of the core grid manager code generate a complex layout such as the one shown in the preceding screenshot. On the other hand, developing this with the pack manager would have been much more tedious.
Another grid option that you can sometimes use is the widget.grid_forget() method. This method can be used to hide a widget from the screen. When you use this option, the widget still exists at its former location, but it becomes invisible. The hidden widget may be made visible again, but the grid options that you originally assigned to the widget will be lost.
Similarly, there is a widget.grid_remove() method that removes the widget, except that in this case, when you make the widget visible again, all of its grid options will be restored.
For a complete grid reference, type the following command in the Python shell:
>>> import tkinter
>>> help(tkinter.Grid)
Where should you use the grid geometry manager?
The grid manager is a great tool for the development of complex layouts. Complex structures can be easily achieved by breaking the container widget into grids of rows and columns and then placing the widgets in grids where they are wanted. It is also commonly used to develop different kinds of dialog box.
Now we will delve into configuring a grid's column and row sizes.
Different widgets have different heights and widths. So, when you specify the position of a widget in terms of rows and columns, the cell automatically expands to accommodate the widget.
Normally, the height of all the grid rows is automatically adjusted so it's the height of its tallest cell. Similarly, the width of all the grid columns is adjusted so it's equal to the width of the widest widget cell.
If you then want a smaller widget to fill a larger cell or to stay on any one side of the cell, you can use the sticky attribute on the widget to control this aspect.
However, you can override this automatic sizing of columns and rows by using the following code:
w.columnconfigure(n, option=value, ...) AND
w.rowconfigure(n, option=value, ...)
Use these to configure the options for a given widget, w, in either the nth column or the nth row, specifying values for the options, minsize, pad, and weight. Note that the numbering of rows begins from 0 and not 1.
The options available are as follows:
Options |
Descriptions |
minsize
|
This is the minimum size of a column or row in pixels. If there is no widget in a given column or row, the cell does not appear in spite of this minsize specification.
|
pad
|
This is the external padding in pixels that will be added to the specified column or row over the size of the largest cell.
|
weight
|
This specifies the relative weight of a row or column and then distributes the extra space. This enables making the row or column stretchable.
For example, the following code distributes two-fifths of the extra space to the first column and three-fifths to the second column:
w.columnconfigure(0, weight=2)
w.columnconfigure(1, weight=3)
|
The columnconfigure() and rowconfigure() methods are often used to implement the dynamic resizing of widgets, especially on resizing the root window.
You cannot use the grid and pack methods together in the same container window. If you try doing that, your program will raise a _tkinter.TclError error.