[PySide] custom paint delegate for table keeps redrawing clicked cell

Frank Rueter frank at ohufx.com
Sun Nov 2 07:44:28 CET 2025


Hi all,

I have this example code below which uses a delegate to paint a selected
row in a QTableWidget with custom colours and a border.
But for some reason that I do not understand the font colours change as
well as you can see in the attached screen recording.
I am particularly curious about why the clicked cell repaints itself split
seconds after my custom paint event (and how I can prevent that).

Any help would be greatly appreciated!

Cheers,
frank

from PySide6.QtWidgets import (
    QApplication, QTableWidget, QTableWidgetItem, QStyledItemDelegate,
QStyleOptionViewItem, QStyle
)
from PySide6.QtGui import QPainter, QPen, QColor

# Dark blue colors for selection
COLORS = {
    "row_border": QColor("#003366"),
    "row_fill": QColor("#336699"),
    "text": QColor("black")
}

class CutTableDelegate(QStyledItemDelegate):
    """Draws a dark blue fill for selected rows.
    """

    #ToDo: the text colour changes when it shouldn't

    def paint(self, painter, option, index):
        option_no_select = QStyleOptionViewItem(option)
        option_no_select.state &= ~QStyle.State_Selected  # prevent
default selection background

        # Draw row background if selected
        if option.state & QStyle.State_Selected:
            table = index.model().parent()
            if table:
                row_rect = table.visualRect(table.model().index(index.row(), 0))
                for col in range(1, table.columnCount()):
                    row_rect =
row_rect.united(table.visualRect(table.model().index(index.row(),
col)))

                painter.setPen(QPen(COLORS["row_border"], 2))
                painter.setBrush(COLORS["row_fill"])
                painter.drawRect(row_rect.adjusted(0, 0, -1, -1))

        # Draw the cell text using fixed color
        painter.save()
        painter.setPen(QPen(COLORS["text"]))
        super().paint(painter, option_no_select, index)
        painter.restore()


if __name__ == "__main__":
    app = QApplication([])

    table = QTableWidget(5, 3)
    table.setHorizontalHeaderLabels(["Shot Name", "Duration", "Status"])
    table.setItemDelegate(CutTableDelegate(table))
    table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)

    # Sample data
    data = [
        ["Shot 1", "10", "Ready"],
        ["Shot 2", "12", "Pending"],
        ["Shot 3", "8", "Done"],
        ["Shot 4", "15", "Ready"],
        ["Shot 5", "5", "Pending"],
    ]

    for row_idx, row_data in enumerate(data):
        for col_idx, text in enumerate(row_data):
            table.setItem(row_idx, col_idx, QTableWidgetItem(text))

    table.resize(500, 300)
    table.show()
    app.exec()


-- 
Frank Rueter  I VFX Supervisor | OHUfx | +64 21 110 7919
                              Aotearoa | New Zealand
                                   www.ohufx.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20251102/b5462772/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: delegate_issues_with_table.mov
Type: video/quicktime
Size: 305157 bytes
Desc: not available
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20251102/b5462772/attachment-0001.mov>


More information about the PySide mailing list