2

I want to customize a QTabWidget, so that every tab has it's own background color. I know, that this cannot be done with stylesheets, so I subclassed QTabBar and changed it's paintEvent. Then, I replaced the default QTabBar of QTabWidget with my own implementation. However, the background color of the tabs doesn't change. Does anybody know what I am missing?

Here is a small demo application which illustrates my problem:

from PyQt4 import QtGui 

import sys

class coloredTabBar(QtGui.QTabBar):
    def __init__(self, parent = None):
        QtGui.QTabBar.__init__(self, parent)

    def paintEvent(self, event):
        p = QtGui.QStylePainter(self)
        painter = QtGui.QPainter(self)
        for index in range(self.count()): #for all tabs
            tab = QtGui.QStyleOptionTabV3() #create styled tab
            self.initStyleOption(tab, index) #initialize with default values
            #change background color to red
            tab.palette.setColor(QtGui.QPalette.Base, QtGui.QColor(255, 0, 0)) 
            p.drawControl(QtGui.QStyle.CE_TabBarTab, tab) #draw tab


class coloredTabWidget(QtGui.QTabWidget):
    def __init__(self, parent = None):
        QtGui.QTabWidget.__init__(self, parent)

        coloredTabs = coloredTabBar()
        self.setTabBar(coloredTabs) #replace default tabBar with my own implementation

if __name__ == "__main__":     
    app = QtGui.QApplication(sys.argv)

    tabWidget = coloredTabWidget()

    tabWidget.addTab(QtGui.QWidget(), "Hello")
    tabWidget.addTab(QtGui.QWidget(), "World")

    tabWidget.show()

    sys.exit(app.exec_())

Kind Regards

Bernhard

user2494129
  • 717
  • 2
  • 13
  • 24

2 Answers2

1

You're using the wrong palette role. You need QPalette.Window, which is the general widget background color, rather than QPalette.Base, which is for more specialized elements like edit-controls:

tab.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(255, 0, 0))

However, you should be aware that painting tabs in this way won't work on all platforms. This is because some Windows and Mac styles use pixmaps when drawing the tabs, and so don't take palette changes into account. See this Qt FAQ for more details.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Thanks for your answer! I tried a few different palette roles (including `QPalette.Window`), but It made no difference on my machine (Windows 7). I also thought about using `QProxyStyle`, but it seems that this module isn't included in PyQt... You seem to have a lot of experience with Py(Qt)...how would you tackle the problem? – user2494129 Mar 23 '14 at 21:20
  • @user2494129. I'm afraid I don't have anything much to add that is not already in that Qt FAQ. The last time I looked at this, the only viable option on Windows was to use a stylesheet. But you can't style individual tabs that way (all tabs get coloured the same), and I think other aspects of the tab styling may be affected. So it's not an ideal solution. – ekhumoro Mar 23 '14 at 21:34
  • No problem, you already helped me a lot with the Qt FAQ! I think I will try to do some low-level painting with QPainter...I don't know if it works, but I think it's worth a try. – user2494129 Mar 23 '14 at 22:50
1

Okay, I think I got something. It is not the prettiest thing, but it does the trick.

If anyone has a better idea on how to solve this problem...let me know.

from PyQt4 import QtGui 
from PyQt4 import QtCore

import sys

class coloredTabBar(QtGui.QTabBar):
    def __init__(self, parent = None):
        QtGui.QTabBar.__init__(self, parent)

    def paintEvent(self, event):
        p = QtGui.QStylePainter(self)
        painter = QtGui.QPainter(self)
        painter.save()
        for index in range(self.count()): #for all tabs

            tabRect = self.tabRect(index)
            tabRect.adjust(-1, 3, -1, -1) #ajust size of every tab (make it smaller)
            if index == 0: #make first tab red 
                color = QtGui.QColor(255, 0, 0)
            elif index == 1: #make second tab yellow
                color = QtGui.QColor(255, 255, 0)
            else: #make all other tabs blue
                color = QtGui.QColor(0, 0, 255)
            if index == self.currentIndex(): #if it's the selected tab
                color = color.lighter(130) #highlight the selected tab with a 30% lighter color
                tabRect.adjust(0, -3, 0, 1) #increase height of selected tab and remove bottom border


            brush = QtGui.QBrush(color)
            painter.fillRect(tabRect, brush)

            painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.black))) #black pen (for drawing the text)
            painter.drawText(tabRect, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter,
                             self.tabText(index))

            painter.setPen(QtGui.QPen(QtGui.QColor(QtCore.Qt.gray))) #gray pen (for drawing the border)
            painter.drawRect(tabRect)
        painter.restore()

class coloredTabWidget(QtGui.QTabWidget):
    def __init__(self, parent = None):
        QtGui.QTabWidget.__init__(self, parent)

        coloredTabs = coloredTabBar()
        self.setTabBar(coloredTabs) #replace default tabBar with my own implementation

if __name__ == "__main__":     
    app = QtGui.QApplication(sys.argv)

    tabWidget = coloredTabWidget()

    tabWidget.addTab(QtGui.QWidget(), "Tab 1")
    tabWidget.addTab(QtGui.QWidget(), "Tab 2")
    tabWidget.addTab(QtGui.QWidget(), "Tab 3")
    tabWidget.addTab(QtGui.QWidget(), "Tab 4")

    tabWidget.show()

    sys.exit(app.exec_())
user2494129
  • 717
  • 2
  • 13
  • 24