Of course! Let's dive deep into QGridLayout in Python using PyQt or PySide. It's one of the most powerful and commonly used layout managers.

What is QGridLayout?
QGridLayout is a layout manager that arranges widgets in a grid of rows and columns. You place widgets into "cells" defined by their row and column coordinates. It's perfect for creating forms, spreadsheets, dashboards, or any UI where you need a structured, two-dimensional arrangement of elements.
Think of it like a spreadsheet or a table. You define how many rows and columns you have, and then you place your widgets into the specific cells.
Key Concepts
- Widget: Any UI element (like a
QPushButton,QLabel,QLineEdit, etc.) that you want to place in the layout. - Cell: A specific intersection of a row and a column.
- Row and Column Indexes: These are zero-based. The top-left cell is at
(0, 0). - Spacing: The amount of empty space between the cells of the grid.
- Margins: The amount of empty space around the outer edge of the entire grid layout.
How to Use QGridLayout: The Core Methods
Here are the primary methods you'll use to interact with a QGridLayout.
addWidget(widget, row, column, rowSpan=1, colSpan=1)
This is the most important method. It adds a widget to the grid.

widget: The widget to add.row: The row index (0-based).column: The column index (0-based).rowSpan(optional): The number of rows the widget should span. Defaults to 1.colSpan(optional): The number of columns the widget should span. Defaults to 1.
Spanning is a powerful feature! It allows a widget to occupy multiple cells, which is essential for creating non-uniform grids.
addWidget(widget, position, alignment=...)
A more concise version where position is a QPoint object (e.g., QPoint(1, 2)).
setSpacing(int spacing)
Sets the spacing between the cells of the grid.
setContentsMargins(left, top, right, bottom)
Sets the margins around the entire grid layout.
setRowStretch(row, stretch)
and
setColumnStretch(column, stretch)
This is crucial for creating flexible layouts. The stretch factor determines how extra space in the layout is distributed.
- A stretch factor of
0means the row/column will not grow. - A higher number means it will claim more of the available extra space.
- This is how you make certain areas of your UI expand while others stay fixed.
Practical Example 1: A Simple Login Form
Let's create a classic login window. This demonstrates basic placement and spanning.
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit, QPushButton, QGridLayout
)
class LoginForm(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('QGridLayout Example')
self.initUI()
def initUI(self):
# Create the layout
layout = QGridLayout()
# Create widgets
label_username = QLabel('Username:')
label_password = QLabel('Password:')
input_username = QLineEdit()
input_password = QLineEdit()
input_password.setEchoMode(QLineEdit.Password) # Hide password input
button_login = QPushButton('Login')
# Add widgets to the grid
#addWidget(widget, row, column)
layout.addWidget(label_username, 0, 0)
layout.addWidget(input_username, 0, 1)
layout.addWidget(label_password, 1, 0)
layout.addWidget(input_password, 1, 1)
# The login button will span both columns
#addWidget(widget, row, column, rowSpan, colSpan)
layout.addWidget(button_login, 2, 0, 1, 2) # Span 1 row, 2 columns
# Set the layout for the main window
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = LoginForm()
window.show()
sys.exit(app.exec_())
Explanation:
- We create a
QGridLayoutinstance. - We create our
QLabels andQLineEdits. - We use
layout.addWidget()to place them.label_usernamegoes at(0, 0)andinput_usernameat(0, 1). - The
button_loginis placed at(2, 0)but we tell it to span1row and2columns usingrowSpan=1, colSpan=2, so it stretches across the bottom.
Practical Example 2: A Flexible Dashboard
This example shows how to use setRowStretch and setColumnStretch to create a responsive layout where the central area expands to fill extra space.
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QPushButton, QGridLayout
)
class Dashboard(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('Flexible Dashboard')
self.initUI()
def initUI(self):
layout = QGridLayout()
# --- Create Widgets ---
# Top Bar
label_title = QLabel("Dashboard Application")
label_title.setStyleSheet("background-color: #3498db; color: white; font-size: 24px; padding: 10px;")
# Sidebar
button_profile = QPushButton("Profile")
button_settings = QPushButton("Settings")
button_logout = QPushButton("Logout")
# Main Content Area
label_content = QLabel("This is the main content area. It will expand to fill available space.")
label_content.setStyleSheet("background-color: #ecf0f1; font-size: 18px; padding: 20px; border: 1px solid #bdc3c7;")
# --- Add Widgets to Grid ---
#addWidget(widget, row, column, rowSpan, colSpan)
layout.addWidget(label_title, 0, 0, 1, 2) # Spans 2 columns
layout.addWidget(button_profile, 1, 0)
layout.addWidget(button_settings, 2, 0)
layout.addWidget(button_logout, 3, 0)
layout.addWidget(label_content, 1, 1, 3, 1) # Spans 3 rows
# --- Configure Stretch Factors ---
# Let the main content area (column 1) expand
layout.setColumnStretch(0, 1) # Sidebar column has low stretch
layout.setColumnStretch(1, 4) # Content column has high stretch
# Let the content area (row 1) expand vertically
layout.setRowStretch(0, 0) # Title row has no stretch
layout.setRowStretch(1, 3) # Content row has high stretch
layout.setRowStretch(2, 0) # Button rows have no stretch
layout.setRowStretch(3, 0)
# Set the layout for the main window
self.setLayout(layout)
self.resize(800, 600) # Give it an initial size to see the effect
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Dashboard()
window.show()
sys.exit(app.exec_())
Explanation:
- Grid Structure: We have a 4x2 grid.
- Stretch Factors:
setColumnStretch(0, 1)andsetColumnStretch(1, 4): This means that for every 5 units of extra horizontal space, 1 unit goes to the sidebar (column 0) and 4 units go to the main content (column 1). This makes the content area much wider.setRowStretch(1, 3): This gives all the extra vertical space to the main content area (row 1), pushing the buttons to the bottom.
- Result: When you resize the window, the title bar and buttons stay a fixed size, while the main content area (
label_content) grows to fill the available space. This is the key to creating professional, resizable interfaces.
Comparison with Other Layouts
| Layout | Best For | Analogy |
|---|---|---|
QHBoxLayout |
Arranging widgets in a single row (horizontally). | A sentence of words. |
QVBoxLayout |
Arranging widgets in a single column (vertically). | A list of items. |
QGridLayout |
Arranging widgets in a 2D grid of rows and columns. | A spreadsheet or a table. |
QFormLayout |
Specifically for creating forms with labels and fields. | A paper form with name, address, etc. (often implemented using QGridLayout underneath). |
QStackedLayout |
Stacking multiple widgets on top of each other, showing only one at a time. | A pile of papers, where you can only look at one at a time. |
Important Tips
- Nested Layouts: You can't put a layout directly into another layout. However, you can put a widget that contains a layout into another layout. The standard way to do this is with a
QWidget. Create aQWidget, set a layout on it (e.g., aQHBoxLayout), add other widgets to that inner layout, and then add theQWidgetto your outerQGridLayout. - Complexity: For very complex UIs, nesting layouts (e.g., a
QVBoxLayoutcontaining aQGridLayoutand aQHBoxLayout) is more maintainable than trying to do everything with one giant grid. - Qt Designer: For complex layouts, using Qt Designer is highly recommended. It's a visual tool that lets you drag and drop widgets and arrange them with layouts, then saves the result to a
.uifile. You can then compile this.uifile into a Python module (usingpyside6-uicorpyuic5) and load it into your application, saving you from writing layout code by hand.
