admin管理员组

文章数量:1320807

I'm trying to set the border colour of checkboxes in a QTableView.


I tried using setStyleSheet, but this just overrides the entire checkbox style, and removes the tick:

table_view.setStyleSheet(
    """
    QTableView::indicator:unchecked {
        border: 2px solid red;
    }
    QTableView::indicator:checked {
        border: 2px solid green;
    }
"""
)

I would basically have to recreate the entire checkbox this way, guess the default properties it has, and find a way to get a tick in there.


Using a QStyleImageDelegate, I can achieve some customizability, without removing the tick:

class CheckboxDelegate(QStyledItemDelegate):
    def __init__(self, border_colour):
        super().__init__()
        self.border_colour = border_colour

    def paint(self, painter, option, index):
        if index.data(Qt.CheckStateRole) is not None:
            checkbox_option = QStyleOptionButton()
            checkbox_option.state |= QStyle.State_Enabled
            checkbox_option.state |= (
                QStyle.State_On if index.data(Qt.CheckStateRole) == Qt.Checked else QStyle.State_Off
            )

            # Draw custom boarder and checkbox
            checkbox_option.rect = option.rect
            painter.save()
            painter.setPen(QColor(self.border_colour))
            painter.drawRect(option.rect)
            QApplication.style().drawControl(QStyle.CE_CheckBox, checkbox_option, painter)
            painter.restore()
        else:
            super().paint(painter, option, index)
delegate = CheckboxDelegate('red')
table_view.setItemDelegateForColumn(1, delegate)

But again, the same problem of having to reimplement the entire checkbox style, but just change one property. Except this also seems unnecessarily complex.


Full code:

from PySide6.QtCore import Qt, QAbstractTableModel
from PySide6.QtWidgets import (
    QStyledItemDelegate,
    QStyle,
    QStyleOptionButton,
    QApplication,
    QTableView,
)
from PySide6.QtGui import QColor


class CheckboxDelegate(QStyledItemDelegate):
    def __init__(self, border_colour):
        super().__init__()
        self.border_colour = border_colour

    def paint(self, painter, option, index):
        if index.data(Qt.CheckStateRole) is not None:
            checkbox_option = QStyleOptionButton()
            checkbox_option.state |= QStyle.State_Enabled
            checkbox_option.state |= (
                QStyle.State_On if index.data(Qt.CheckStateRole) == Qt.Checked else QStyle.State_Off
            )

            # Modify border color
            checkbox_option.rect = option.rect
            painter.save()
            painter.setPen(QColor(self.border_colour))
            painter.drawRect(option.rect)
            QApplication.style().drawControl(QStyle.CE_CheckBox, checkbox_option, painter)
            painter.restore()
        else:
            super().paint(painter, option, index)


class TableModel(QAbstractTableModel):
    def __init__(self, data, headers, parent=None):
        super().__init__(parent)
        self._data = data
        self._headers = headers

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

    def columnCount(self, parent=None):
        return len(self._headers)

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

        value = self._data[index.row()][index.column()]
        if role == Qt.DisplayRole:
            return value
        if role == Qt.CheckStateRole and index.column() == 1:
            return Qt.Checked if value else Qt.Unchecked

        return None

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return self._headers[section]
            if orientation == Qt.Vertical:
                return f"Row {section + 1}"

        return None

    def setData(self, index, value, role):
        if not index.isValid():
            return False

        if role == Qt.CheckStateRole and index.column() == 1:
            self._data[index.row()][index.column()] = bool(value)
            self.dataChanged.emit(index, index, [role])
            return True

        return False

    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags

        if index.column() == 1:
            return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable

        return Qt.ItemIsEnabled


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)

    data = [
        ["Row1", True],
        ["Row2", False],
        ["Row3", True],
    ]
    headers = ["Text", "Checkbox"]

    model = TableModel(data, headers)
    table_view = QTableView()
    table_view.setModel(model)

    # # Set the style for QTableView checkboxes
    # table_view.setStyleSheet(
    #     """
    #     QTableView::indicator:unchecked {
    #         border: 2px solid red;
    #     }
    #     QTableView::indicator:checked {
    #         border: 2px solid green;
    #     }
    # """
    # )

    # # Set custom delegate for the checkbox column
    # delegate = CheckboxDelegate("red")
    # table_view.setItemDelegateForColumn(1, delegate)

    table_view.show()
    sys.exit(app.exec())

本文标签: