QTableView Align Currency Column Right with QStyledItemDelegate

Use Qt.TextAlignmentRole in your model's data() method to align columns in a QTableView
Heads up! You've already completed this tutorial.

When you're building a table with financial data, you'll want your currency columns right-aligned. It's a small visual detail, but it makes numeric data much easier to scan and compare. If you're using QTableWidget, you can set alignment directly on each QTableWidgetItem. But with QTableView and a custom QAbstractTableModel, the approach is a little different.

The alignment for cells in a QTableView is controlled by the model, specifically by responding to Qt.TextAlignmentRole in your model's data() method. Let's walk through how this works, starting with the basics and building up to a complete working example with a QStyledItemDelegate for displaying currency values.

Returning alignment from the model

Your model's data() method already handles Qt.DisplayRole to return text for each cell. To control alignment, you add another check for Qt.TextAlignmentRole and return the desired alignment flags for specific columns.

Here's the pattern:

python
def data(self, index, role):
    if role == Qt.DisplayRole:
        return self._data[index.row()][index.column()]

    if role == Qt.TextAlignmentRole:
        if index.column() == 2:  # e.g., your currency column
            return Qt.AlignRight | Qt.AlignVCenter

When Qt asks the model "how should this cell be aligned?", this code answers with the alignment flags. The view takes care of the rest.

A complete working example

Let's put together a full example: a QTableView displaying a list of items with descriptions and prices. The price column will be right-aligned. If you're new to using QTableView with custom models, you may want to read through the Model/View architecture tutorial first.

python
import sys

from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt
from PyQt6.QtWidgets import (
    QApplication,
    QDoubleSpinBox,
    QMainWindow,
    QStyledItemDelegate,
    QTableView,
    QVBoxLayout,
    QWidget,
)


SAMPLE_DATA = [
    ["Espresso", "Coffee", 3.50],
    ["Croissant", "Pastry", 2.75],
    ["Orange Juice", "Beverage", 4.00],
    ["Avocado Toast", "Food", 8.50],
    ["Cappuccino", "Coffee", 4.25],
]

HEADERS = ["Item", "Category", "Price"]
CURRENCY_COLUMN = 2


class ItemTableModel(QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data

    def rowCount(self, parent=QModelIndex()):
        return len(self._data)

    def columnCount(self, parent=QModelIndex()):
        return len(self._data[0]) if self._data else 0

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None

        value = self._data[index.row()][index.column()]

        if role == Qt.DisplayRole:
            if index.column() == CURRENCY_COLUMN:
                return f"${value:.2f}"
            return str(value)

        if role == Qt.EditRole:
            return value

        if role == Qt.TextAlignmentRole:
            if index.column() == CURRENCY_COLUMN:
                return int(Qt.AlignRight | Qt.AlignVCenter)

        return None

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole and index.isValid():
            self._data[index.row()][index.column()] = value
            self.dataChanged.emit(index, index, [role])
            return True
        return False

    def flags(self, index):
        base_flags = super().flags(index)
        if index.column() == CURRENCY_COLUMN:
            return base_flags | Qt.ItemIsEditable
        return base_flags

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return HEADERS[section]
        return None


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Currency Alignment Example")
        self.setMinimumSize(450, 300)

        # Set up the model and view.
        self.model = ItemTableModel(SAMPLE_DATA)
        self.table = QTableView()
        self.table.setModel(self.model)

        # Stretch columns to fill the available space.
        header = self.table.horizontalHeader()
        header.setStretchLastSection(True)

        layout = QVBoxLayout()
        layout.addWidget(self.table)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

When you run this, you'll see a table where the "Item" and "Category" columns are left-aligned (the default), and the "Price" column is right-aligned. Double-click a price cell to edit it — the spin box editor is also right-aligned, so the experience feels consistent.

QTableView with right-aligned currency column

How it all fits together

There are three pieces working together here:

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick — (PyQt6 Edition) The hands-on guide to making apps with Python — Save time and build better with this book. Over 15K copies sold.

Get the book

  1. The model's data() method handles Qt.TextAlignmentRole to tell the view how to align each cell. This controls the display alignment — what you see when you're just looking at the table.

  2. The model's data() method with Qt.DisplayRole formats the value with a dollar sign and two decimal places for display.

Aligning multiple columns

If you have several numeric columns you want to right-align, you can check against a list or set of column indices:

python
CURRENCY_COLUMNS = {2, 3, 5}  # columns to right-align

def data(self, index, role=Qt.DisplayRole):
    # ... other role handling ...

    if role == Qt.TextAlignmentRole:
        if index.column() in CURRENCY_COLUMNS:
            return int(Qt.AlignRight | Qt.AlignVCenter)

This scales nicely — you define your numeric columns once and the alignment follows automatically.

Summary

Aligning columns in a QTableView is handled entirely within the model. By responding to Qt.TextAlignmentRole in your data() method, you can control alignment per-column (or even per-cell) without touching the delegate's paint() method. For more on working with table views — including displaying data from numpy and pandas — see the QTableView with numpy and pandas tutorial. If you need to make your table cells editable, take a look at editing a PyQt6 QTableView. You can also sort and filter your table data using a proxy model for a more polished experience.d

Over 15,000 developers have bought Create GUI Applications with Python & Qt!
Create GUI Applications with Python & Qt6
Get the book

Downloadable ebook (PDF, ePub) & Complete Source code

[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]
Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak
Martin Fitzpatrick

QTableView Align Currency Column Right with QStyledItemDelegate was written by Martin Fitzpatrick.

Martin Fitzpatrick is the creator of Python GUIs, and has been developing Python/Qt applications for the past 12+ years. He has written a number of popular Python books and provides Python software development & consulting for teams and startups.