One option would be to implement your own tab bar (as explained here).
Anyway, I find more useful and cleaner the use of a proxy style, since it allows you to partially override the painting without need to use inheritance for the tab bar. It will allow you also to easily apply the new style to existing controls.
It can be something like:
class TabBackgroundProxyStyle : public QProxyStyle {
public:
TabBackgroundProxyStyle(const QString& base_style_name, const QMap<QString, QBrush>& backgrounds)
: QProxyStyle(base_style_name),
m_backgrounds(backgrounds) {
}
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const override {
if (element == CE_TabBarTab) {
if (auto tab = qstyleoption_cast<const QStyleOptionTab*>(option)) {
if (m_backgrounds.contains(tab->text)) {
QStyleOptionTab opt(*tab);
opt.palette.setBrush(QPalette::Background, m_backgrounds[tab->text]);
return QProxyStyle::drawControl(element, &opt, painter, widget);
}
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
private:
const QMap<QString, QBrush> m_backgrounds;
};
To use it, just create the style with the appropriate tabs-color mapping (examples using C++11):
auto theTabWidget = new QTabWidget();
for (int ii = 0; ii < 10; ++ii) theTabWidget->addTab(new QWidget(), QString("Tab %1").arg(ii + 1));
const QMap<QString, QBrush> backgrounds = {
{"Tab 2", QBrush(Qt::red)},
{"Tab 3", QBrush("#c0b050")},
};
theTabWidget->tabBar()->setStyle(new TabBackgroundProxyStyle("", backgrounds));
If your user interface allows the tab's text to change on runtime (e.g., on-the-fly translations, or the text is a filename...) then you must modify the map accordingly.
The use of the tab's label for indexing is because the style option doesn't store any other direct information about the tab (not even the associated widget, because QTabBar
is in charge of rendering only the tabs, it is not the container).
Another option would be to check the tab's rectangle, not much time-consuming for tab bars with just a few dozens of tabs, and more versatile if you don't want to deal with labels:
class TabBackgroundProxyStyle : public QProxyStyle {
public:
TabBackgroundProxyStyle(const QString& base_style_name, const QMap<int, QBrush>& backgrounds)
: QProxyStyle(base_style_name),
m_backgrounds(backgrounds) {
}
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const override {
if (element == CE_TabBarTab) {
if (auto tab = qstyleoption_cast<const QStyleOptionTab*>(option)) {
auto tabBar = qobject_cast<const QTabBar*>(widget);
for (auto index : m_backgrounds.keys()) {
if (tab->rect == tabBar->tabRect(index)) {
QStyleOptionTab opt(*tab);
opt.palette.setBrush(QPalette::Background, m_backgrounds[index]);
return QProxyStyle::drawControl(element, &opt, painter, widget);
}
}
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
private:
const QMap<int, QBrush> m_backgrounds;
};
Use:
auto theTabWidget = new QTabWidget();
for (int ii = 0; ii < 10; ++ii) theTabWidget->addTab(new QWidget(), QString("Tab %1").arg(ii + 1));
const QMap<int, QBrush> backgrounds = {
{1, QBrush(Qt::red)},
{4, QBrush("#c0b050")},
};
theTabWidget->tabBar()->setStyle(new TabBackgroundProxyStyle("", backgrounds));
Full source code can be downloaded from https://github.com/cbuchart/stackoverflow/tree/master/54070408-change-color-of-single-qtabwidget-tab
IMPORTANT: The main drawback of this solution is that it doesn't mix well with existing stylesheet for tabs: you have to disable/comment the stylesheets for QTabBar::tab
in order to be able to apply the style.
QTabWidget
usesQTabBar
to manage the tabs. (QTabWidget
on woboq.org) Hence, I looked intoQTabBar::paintEvent()
on woboq. So, a solution could be to overloadQTabBar
and overrideQTabBar::paintEvent()
tweaking the painting to your intention. – Scheff's Cat