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())