6

I have a QTableWidget where I would like to color individual horizontal header items based on some criterion.

What I have come up with so far:

stylesheet = "::section{Background-color:rgb(190,1,1)}"
self.ui.Table.horizontalHeader().setStyleSheet(stylesheet)

This works, however it colors all headers simultaneously without me being able to change the color of an individual header. So the next logical step would be:

self.ui.Table.horizontalHeaderItem(0).setStyleSheet(stylesheet) 

This does not work, as a single header item does not support setting a stylesheet.

Finally:

self.ui.Table.horizontalHeaderItem(0).setBackgroundColor(QtCore.Qt.red)

This runs just fine without python complaining, however it does not seem to have any effect on the background color whatsoever.

I already looked at this answer, it is what sparked my first attempt. However it only deals with coloring all headers with the same color.

How can I color the headers individually?

3 Answers 3

4

You can do this by using the following recipe:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent=None,initials=None):
        QtWidgets.QFrame.__init__(self, parent)
        self.table = QtWidgets.QTableWidget(5,3,self)
        self.table.move(30,30)
        self.table.resize(400,300)

        item1 = QtWidgets.QTableWidgetItem('red')
        item1.setBackground(QtGui.QColor(255, 0, 0))
        self.table.setHorizontalHeaderItem(0,item1)

        item2 = QtWidgets.QTableWidgetItem('green')
        item2.setBackground(QtGui.QColor(0, 255, 0))
        self.table.setHorizontalHeaderItem(1,item2)

        item3 = QtWidgets.QTableWidgetItem('blue')
        item3.setBackground(QtGui.QColor(0, 0, 255))
        self.table.setHorizontalHeaderItem(2,item3)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle(QtWidgets.QStyleFactory.create('Fusion')) # won't work on windows style.
    Frame = MyFrame(None)
    Frame.resize(500,400)
    Frame.show()
    app.exec_()

, that will result in this:

Different colors for header items in QTableWidget

One thing you must consider is that Windows style does not let you do this. This is the reason why I had to change the style to Fusion.

Sign up to request clarification or add additional context in comments.

4 Comments

Unfortunately I am forced to use PyQt4. After I adjusted all the imports, I get a table with uncoloured headers. I guess this feature just does not seem to work with PyQt4. I will wait some time if anyone comes up with a solution for PyQt4. Otherwise I will mark yours as the accepted answer for any PyQt5 users struggling with this.
Are you sure? Excluding imports everything (regarding this example) should be working the same way. Did you change the app style? "app.setStyle(QtWidgets.QStyleFactory.create('Fusion'))" Try with other styles, since I don't know if the permissions changed between Qt versions. For "Windows" style I'm reasonably sure it won't work, no matter the Qt version.
you are right, it does work with plastique and cleanlooks, not with fusion or windows however
Hi, is it possible to change the counter column on the left only? (1, 2, 3, 4...)
2

setBackground seems to have no effect When used in header

See this: https://forum.qt.io/topic/74609/cannot-set-the-backgroud-color-of-the-horizontalheaderitem-of-qtablewidget/2

I wrote this small app; font type and size and foreground color take effect.

from PyQt4 import QtGui
from PyQt4.QtGui import QFont

app = QtGui.QApplication([])

columns = ['Column 0', 'Column 1', 'Column 2']
items = [['Row%s Col%s' % (row, col) for col in range(len(columns))] for row in range(1)]

view = QtGui.QTableWidget()

view.setColumnCount(len(columns))
view.setHorizontalHeaderLabels(columns)
view.setRowCount(len(items))
for row, item in enumerate(items):
    for col, column_name in enumerate(item):
        item = QtGui.QTableWidgetItem("%s" % column_name)
        view.setItem(row, col, item)
    view.setRowHeight(row, 16)

fnt = QFont()
fnt.setPointSize(15)
fnt.setBold(True)
fnt.setFamily("Arial")

item1 = view.horizontalHeaderItem(0)
item1.setForeground(QtGui.QColor(255, 0, 0))
item1.setBackground(QtGui.QColor(0, 0, 0))  # Black background! does not work!!
item1.setFont(fnt)

item2 = view.horizontalHeaderItem(1)
item2.setForeground(QtGui.QColor(0, 255, 0))
item2.setFont(fnt)

item3 = view.horizontalHeaderItem(2)
item3.setForeground(QtGui.QColor(255, 0, 255))

view.setHorizontalHeaderItem(0, item1)
view.setHorizontalHeaderItem(1, item2)
view.setHorizontalHeaderItem(2, item3)
view.show()
app.exec_()

enter image description here

1 Comment

Add app.setStyle (QStyleFactory.create ('Fusion')) after app = QApplication ([]) and setBackground will start working.
1

Here is a modification of armatita's answer working with the default Windows style:

import sys
from PySide6 import QtGui, QtWidgets


class ColoredTableHeaderStyle(QtWidgets.QProxyStyle):
    def drawControl(self, element, option, painter, widget=None):
        if element == QtWidgets.QStyle.ControlElement.CE_HeaderSection and isinstance(widget, QtWidgets.QHeaderView):
            fill = option.palette.brush(QtGui.QPalette.ColorRole.Window)  # the Qt implementation actually sets the background brush on the Window color role, the default Windows style simply ignores it
            painter.fillRect(option.rect, fill)  # fill the header section with the background brush
        else:
            self.baseStyle().drawControl(element, option, painter, widget)  # use the default implementation in all other cases


class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent=None):
        QtWidgets.QFrame.__init__(self, parent)
        self.table = QtWidgets.QTableWidget(5, 3, self)
        self.table.move(30, 30)
        self.table.resize(400, 300)

        item1 = QtWidgets.QTableWidgetItem('red')
        item1.setBackground(QtGui.QColor(255, 0, 0))
        self.table.setHorizontalHeaderItem(0, item1)

        item2 = QtWidgets.QTableWidgetItem('green')
        item2.setBackground(QtGui.QColor(0, 255, 0))
        self.table.setHorizontalHeaderItem(1, item2)

        item3 = QtWidgets.QTableWidgetItem('blue')
        item3.setBackground(QtGui.QColor(0, 0, 255))
        self.table.setHorizontalHeaderItem(2, item3)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle(ColoredTableHeaderStyle(app.style()))  # use the proxy style reimplementing the drawing of table headers, otherwise identical with the default Windows style
    Frame = MyFrame(None)
    Frame.resize(500, 400)
    Frame.show()
    app.exec_()

It can be refined by using a custom subclass of QHeaderView to modify only the horizontal header to be colored. It also works for a QTableView.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.