Reputation: 71
I've found a way to do css based cell styling in a TableView based on contents in the cell. The following code shows an example:
#!/usr/bin/python3
from PyQt5 import QtWidgets, QtGui, QtCore
class_values = ["zero", "one", "two"]
class Cell(QtWidgets.QWidget):
def initFromItem(self, item):
self.setProperty('dataClass', class_values[int(item.text())])
class TDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, *a):
super(TDelegate, self).__init__(*a)
self.cell = Cell(self.parent())
def paint(self, painter, option, index):
item = index.model().itemFromIndex(index)
self.cell.initFromItem(item)
self.initStyleOption(option, index)
style = option.widget.style() if option.widget else QtWidgets.QApplication.style()
style.unpolish(self.cell)
style.polish(self.cell)
style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, painter, self.cell)
class TTableModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super(TTableModel, self).__init__(parent)
for i in range(5):
self.appendRow([QtGui.QStandardItem(str((x+i) % 3)) for x in range(5)])
class TTableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super(TTableView, self).__init__(parent)
self.setItemDelegate(TDelegate(self))
class Main(QtWidgets.QMainWindow):
def __init__(self):
super(Main, self).__init__()
self.table = TTableView(self)
self.model = TTableModel(self)
self.table.setModel(self.model)
self.setCentralWidget(self.table)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet("""
Cell[dataClass=zero]::item { background-color: gray; }
Cell[dataClass=one]::item { background-color: green; font-style: italic }
Cell[dataClass=two]::item { font-weight: bold }
""")
mainWin = Main()
mainWin.show()
sys.exit(app.exec_())
This generates a table like this:
TableView with per cell styling
The problem is that while the colours work, the font styling has no effect. What am I doing wrong? How could I improve my code? And how does it work? For example, why does the CSS selector have to include the ::item
. All answers gratefully received. But please bear in mind that the need for CSS based styling is essential to the project.
Upvotes: 2
Views: 1805
Reputation: 71
This is due to a bug in qt (v5.9.5) that ignores all font styling information when creating a CE_ItemViewItem
(see QStyleSheetStyle::drawControl
). Cheating by creating something else like a CE_ToolBoxTabLabel
(which does correct handling of fonts in drawControl
) does get you font formatting, but gets you on the colour because the rendering uses the button face palette, not the one specified in the option (or associated CSS). So you can have one or the other but not both. I know of no workaround.
As to how this works. In QStyleSheetStyle::drawControl
for a CE_ItemViewItem
the CSS for the subrole of ::item
is looked up and if present, applied to a copy of the option (but not the font styling), and then the Item is drawn based on the updated option and its updated palette. Unfortunately there is no way to break into this code since there is no way to apply stylesheets from PyQt (since QStyleSheet is not part of the public API of Qt).
Upvotes: 1