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:

  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

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick

(PyQt6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!

More info Get the book

Martin Fitzpatrick

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

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.