My GUI is built by QTableView's.
Each QTableView has a QStyledItemDelegate.
In the QStyledItemDelegate the background color will be changed with:
def initStyleOption(self, option, index):
super(ValidatedIntItemDelegate, self).initStyleOption(option, index)
option.backgroundBrush = self.calculate_color_for_column(index)
Detail: self.calculate_color_for_column(index)
just does the validation of the cell value, dependent of the validity, a different color is returned.
All background coloring is working perfect as long I just edit within the same table. If I select a cell in another table, the last selected cell in the old table remains with a grey background not coming from my validation.
Scenario:
The cells not updating correctly the background color are the ones
So, how to catch this state and make sure the backround reflects the color returned from self.calculate_color_for_column(index)
?
What you are seeing is not the background not being updated, but the highlight color that is used to show the selection.
In order to ensure that the actual selected item can always be identified, the selection always has the same color, and completely disregards the background of the item. This is probably done for reasons related to UX aspects: for instance, if you use a color with alpha for the selection, you may end up confusing items that are not selected with other that are, but have a color that mixed up with the selection becomes similar to the others.
Since you're using quite pale colors, a possibility could be to use a darker version of the color.
To avoid inconsistency between styles, though, that color won't be used for the item background (the option.backgroundBrush
) but for the option palette, using the Normal
and Inactive
roles with different values of "darkness".
class Delegate(QStyledItemDelegate):
def initStyleOption(self, opt, index):
super().initStyleOption(opt, index)
if opt.backgroundBrush.style() and opt.state & QStyle.State_Selected:
color = opt.backgroundBrush.color()
opt.palette.setColor(QPalette.Active, QPalette.Highlight,
color.darker(150))
opt.palette.setColor(QPalette.Inactive, QPalette.Highlight,
color.darker(125))
Another possibility would be what written above: use a blend of the background and the palette brush.
Since, as explained, the delegate always ignores the color whenever the item is selected, we need to work around this:
PE_PanelItemViewItem
without the State_Selected
flag, so that it paints the background as expected;initStyleOption()
and change the alpha of the Highlight
roles;class Delegate(QStyledItemDelegate):
def initStyleOption(self, opt, index):
super().initStyleOption(opt, index)
if opt.backgroundBrush.style() and opt.state & QStyle.State_Selected:
normal = opt.palette.color(QPalette.Active, QPalette.Highlight)
normal.setAlphaF(.5)
opt.palette.setColor(QPalette.Active, QPalette.Highlight, normal)
inactive = opt.palette.color(QPalette.Inactive, QPalette.Highlight)
inactive.setAlphaF(.5)
opt.palette.setColor(QPalette.Inactive, QPalette.Highlight, inactive)
def paint(self, qp, opt, index):
# we should *never* change the option provided in the arguments when
# doing painting: that option is always reused for other items, and
# its properties are not always cleared
vopt = QStyleOptionViewItem(opt)
self.initStyleOption(vopt, index)
widget = opt.widget
style = widget.style()
if vopt.backgroundBrush.style() and vopt.state & style.State_Selected:
vopt.state &= ~style.State_Selected
style.drawPrimitive(style.PE_PanelItemViewItem, vopt, qp, widget)
# now we *do* use the original option
super().paint(qp, opt, index)