Tkinter Grid Layout
Deep dive · part of Python Tkinter
The grid geometry manager arranges widgets in rows and columns - perfect for forms. Use sticky to anchor cells and columnconfigure(weight=...)/rowconfigure to control how empty space is distributed when the window resizes.
grid places widgets in row/column cells—ideal for forms and dashboards. Unlike pack, grid gives precise alignment; combine columnconfigure(rowconfigure) weight so extra space distributes when users resize the window.
sticky options (nsew) stretch widgets within cells; padx/pady add breathing room. Mixing pack and grid in the same parent causes layout errors—pick one manager per container.
Production code combines this topic with logging, tests, and clear module boundaries so refactors stay safe when requirements grow.
grid(row=, column=) addresses cells; rowspan and columnspan merge cells.
sticky='ew' makes Entry widgets expand horizontally with window.
columnconfigure(1, weight=1) marks column 1 as elastic.
ttk widgets themed separately from tk but share geometry managers.
uniform group sizes columns equally for calculator-style UIs.
in_ option targets child frames as grid parents for nested layouts.
Build forms label column 0 right-aligned (sticky='e'), inputs column 1 sticky='ew'. Put action buttons on a footer row with columnspan across all columns.
High-DPI displays may need ttk scaling on Windows—test on target OS.
Plan tab order row-major for keyboard users; pair labels with entries using consistent grid rows.
Nested Frame grids keep complex forms maintainable—outer regions, inner field grids.
Read the parent tutorial on pythondeck.com for runnable snippets, then reproduce them locally in a virtual environment with pinned dependency versions matching your deployment target.
When pairing with teammates, agree on one idiomatic pattern per concern—mixed styles in one repo slow reviews and invite subtle integration bugs during merges.
pack and grid in same Frame—Tkinter raises confusing errors.
Forgetting weight=1 so entries stay tiny when window grows.
Overlapping widgets by reusing same row/column without removing old widget.
Hard-coding pixel sizes only—no resize behavior on laptops.
Sketch row/column indices on paper before coding complex forms.
Nest Frame widgets: outer grid for regions, inner grid for fields.
Use ttk for modern look; reserve tk Canvas for custom drawing.
Call root.columnconfigure(0, weight=1) on root for single expanding panel.
Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.
The program below demonstrates login form. Read the comments on each line, run the code, then change names or values to see how the output shifts.
# Example: Login form
# Run in the REPL or save as a .py file and execute with python.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Login")
root.columnconfigure(1, weight=1)
ttk.Label(root, text="User:").grid(row=0, column=0, sticky="e", padx=6, pady=4)
ttk.Entry(root).grid(row=0, column=1, sticky="ew", padx=6)
ttk.Label(root, text="Pass:").grid(row=1, column=0, sticky="e", padx=6, pady=4)
ttk.Entry(root, show="*").grid(row=1, column=1, sticky="ew", padx=6)
ttk.Button(root, text="Sign in").grid(row=2, column=0, columnspan=2, pady=8)
root.mainloop()
This sample walks through resizable layout in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.
# Example: Resizable layout
# Run in the REPL or save as a .py file and execute with python.
import tkinter as tk
root = tk.Tk(); root.geometry("400x250")
root.rowconfigure(0, weight=1); root.columnconfigure(0, weight=1)
text = tk.Text(root)
text.grid(row=0, column=0, sticky="nsew")
tk.Button(root, text="Save").grid(row=1, column=0, sticky="e", padx=4, pady=4)
root.mainloop()
Here is a hands-on illustration of login grid. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.
# grid() places widgets in row/column cells
import tkinter as tk # tk
from tkinter import ttk # themed widgets
root = tk.Tk(); root.title("Login") # window
root.columnconfigure(1, weight=1) # stretch column 1
ttk.Label(root, text="User:").grid(row=0, column=0, sticky="e", padx=6) # label
ttk.Entry(root).grid(row=0, column=1, sticky="ew", padx=6) # entry stretches
ttk.Label(root, text="Pass:").grid(row=1, column=0, sticky="e", padx=6) # second row
ttk.Entry(root, show="*").grid(row=1, column=1, sticky="ew", padx=6) # password
ttk.Button(root, text="Sign in").grid(row=2, column=0, columnspan=2, pady=8) # button
print("grid configured") # skip mainloop in CI
The program below demonstrates resize weights. Read the comments on each line, run the code, then change names or values to see how the output shifts.
# rowconfigure/columnconfigure weight distributes extra space
import tkinter as tk # tkinter
root = tk.Tk(); root.geometry("300x200") # size
root.rowconfigure(0, weight=1); root.columnconfigure(0, weight=1) # stretch center
text = tk.Text(root) # multiline editor
text.grid(row=0, column=0, sticky="nsew") # fill cell
tk.Button(root, text="Save").grid(row=1, column=0, sticky="e") # footer button
print("resize weights set") # done
Related deep dives on Python Tkinter: