How to Arrange Widgets Using QGridLayout in PyQt6?

Recently in a Python webinar, someone asked me a question on arranging widgets. After researching various methods, I explained them QGridLayout in PyQt6 . In this tutorial, I will explain how to arrange widgets using QGridLayout in PyQt6 along with suitable examples and screenshots.

QGridLayout in PyQt6

QGridLayout is a layout manager that arranges widgets in a grid pattern of rows and columns. Unlike simpler layouts like QVBoxLayout or QHBoxLayout, QGridLayout gives you precise control over widget positioning by allowing you to specify exact coordinates for each element.

Read How to Create QPushButton Widget in PyQt6?

Key Advantages of QGridLayout:

  • Two-dimensional arrangement – position widgets by row and column coordinates
  • Cell spanning – widgets can span multiple rows or columns
  • Alignment control – adjust how widgets align within their cells
  • Responsive design – grid cells automatically resize with the window
  • Precise positioning – allows for complex layouts without nested layout managers

Method 1: Basic QGridLayout Implementation

Let’s start with a simple implementation to understand the core concepts:

import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, 
                            QGridLayout, QPushButton, QLabel)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Basic QGridLayout Example")
        self.setGeometry(100, 100, 400, 300)

        # Create central widget and grid layout
        central_widget = QWidget()
        grid_layout = QGridLayout(central_widget)

        # Add widgets to specific grid positions (row, column)
        grid_layout.addWidget(QLabel("Name:"), 0, 0)
        grid_layout.addWidget(QLabel("John Smith"), 0, 1)

        grid_layout.addWidget(QLabel("Email:"), 1, 0)
        grid_layout.addWidget(QLabel("john.smith@example.com"), 1, 1)

        grid_layout.addWidget(QPushButton("Save"), 2, 0)
        grid_layout.addWidget(QPushButton("Cancel"), 2, 1)

        self.setCentralWidget(central_widget)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

You can see the output in the screenshot below

Arrange Widgets Using QGridLayout in PyQt6

In this basic example, I’ve created a simple form layout using QGridLayout with three rows and two columns. The key method to note is addWidget(), which takes three parameters:

  • The widget to add
  • The row position (starting from 0)
  • The column position (starting from 0)

This allows us to create a clean, aligned form without the need for nested layouts.

Check out How to Create QLabel Widget in PyQt6?

Method 2: Span Rows and Columns

One of the most efficient features of QGridLayout is the ability to have widgets span multiple rows or columns. This is perfect for creating complex forms and dashboards:

import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, 
                            QGridLayout, QPushButton, QLabel, 
                            QLineEdit, QTextEdit)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Spanning Rows and Columns")
        self.setGeometry(100, 100, 500, 400)

        central_widget = QWidget()
        grid_layout = QGridLayout(central_widget)

        # Title spanning two columns
        title = QLabel("Boston Customer Registration Form")
        title.setStyleSheet("font-size: 16pt; font-weight: bold;")
        grid_layout.addWidget(title, 0, 0, 1, 2)  # row, col, rowspan, colspan

        # Form fields
        grid_layout.addWidget(QLabel("First Name:"), 1, 0)
        grid_layout.addWidget(QLineEdit(), 1, 1)

        grid_layout.addWidget(QLabel("Last Name:"), 2, 0)
        grid_layout.addWidget(QLineEdit(), 2, 1)

        grid_layout.addWidget(QLabel("Comments:"), 3, 0)
        # Text edit spanning 2 rows
        comments = QTextEdit()
        grid_layout.addWidget(comments, 3, 1, 2, 1)  # spans 2 rows

        # Button row
        grid_layout.addWidget(QPushButton("Submit"), 5, 0)
        grid_layout.addWidget(QPushButton("Clear Form"), 5, 1)

        self.setCentralWidget(central_widget)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

You can see the output in the screenshot below

How to Arrange Widgets Using QGridLayout in PyQt6

In this example, I’ve expanded the addWidget() method to use two additional parameters:

  • The row span (how many rows the widget occupies)
  • The column span (how many columns the widget occupies)

The title spans two columns (colspan=2), and the comments text area spans two rows (rowspan=2). This technique gives you tremendous flexibility in designing complex layouts.

Read Basic Widgets in PyQt6

Method 3: Control Spacing and Alignment

For professional-looking UIs, controlling the spacing and alignment within a grid is essential:

import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, 
                            QGridLayout, QPushButton, QLabel, 
                            QLineEdit)
from PyQt6.QtCore import Qt

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Spacing and Alignment in QGridLayout")
        self.setGeometry(100, 100, 500, 300)

        central_widget = QWidget()
        grid_layout = QGridLayout(central_widget)

        # Set spacing for the entire grid
        grid_layout.setSpacing(15)  # 15 pixels between cells

        # Set margins for the layout (left, top, right, bottom)
        grid_layout.setContentsMargins(20, 20, 20, 20)

        # Add widgets with different alignments
        label1 = QLabel("Username:")
        grid_layout.addWidget(label1, 0, 0, alignment=Qt.AlignmentFlag.AlignRight)

        grid_layout.addWidget(QLineEdit(), 0, 1)

        label2 = QLabel("Password:")
        grid_layout.addWidget(label2, 1, 0, alignment=Qt.AlignmentFlag.AlignRight)

        grid_layout.addWidget(QLineEdit(), 1, 1)

        # Add buttons with different alignments
        save_btn = QPushButton("Chicago Login")
        grid_layout.addWidget(save_btn, 2, 0, 1, 2, 
                            alignment=Qt.AlignmentFlag.AlignCenter)

        self.setCentralWidget(central_widget)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

You can see the output in the screenshot below

Arrange Widgets Using QGridLayout in PyQt6 alignment

In this example, I’ve introduced several important spacing and alignment techniques:

  1. setSpacing(pixels): Controls the gap between cells in the grid
  2. setContentsMargins(left, top, right, bottom): Sets padding around the entire layout
  3. The optional alignment parameter: Controls how widgets align within their cells

These methods allow for fine-tuned control over the visual appearance of your UI, making it both functionally and aesthetically pleasing.

Check out How to Create Icons for Windows in PyQt6?

Method 4: Create a Complex Dashboard Layout

When building real-world applications, especially admin panels, dashboards, or data-driven interfaces, you often need to combine multiple layouts — such as horizontal, vertical, and grid layouts — into one complex structure.

import sys
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QListWidget, QTextEdit
)

class DashboardWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        # -------- Main Layout (Vertical) --------
        main_layout = QVBoxLayout()

        # -------- Header --------
        header = QLabel("📊 Dashboard")
        header.setStyleSheet("font-size: 24px; font-weight: bold; padding: 10px;")
        main_layout.addWidget(header)

        # -------- Content Layout (Horizontal) --------
        content_layout = QHBoxLayout()

        # Sidebar (List of navigation options)
        sidebar = QListWidget()
        sidebar.addItems(["Overview", "Reports", "Settings"])
        sidebar.setMaximumWidth(150)
        content_layout.addWidget(sidebar)

        # Main Content Area (TextEdit to represent dynamic content)
        self.content_area = QTextEdit()
        self.content_area.setPlaceholderText("Main content goes here...")
        content_layout.addWidget(self.content_area)

        # Add content layout to main layout
        main_layout.addLayout(content_layout)

        # -------- Footer --------
        footer = QPushButton("Logout")
        footer.setStyleSheet("margin: 10px;")
        main_layout.addWidget(footer)

        # Set main layout
        self.setLayout(main_layout)
        self.setWindowTitle("Complex Dashboard Layout")
        self.setGeometry(100, 100, 600, 400)

# Run the app
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DashboardWindow()
    window.show()
    sys.exit(app.exec())

Nesting Layouts show how vertical and horizontal layouts can work together.

Read Types of Windows in PyQt6

Conclusion

In this tutorial, I explained how to arrange widgets using QGridLayout in PyQt6. I discussed four important methods to achieve this task such as basic QGridLayout implementation, span rows and columns, control spacing and alignment, and creating a complex dashboard layout.

You may read:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.