Reputation: 168
I am trying to edit style of the header of a QTreeWidget
.
I found that I can edit it with QHeaderView::section
and there, edit background, colors, border...
However, I would like to edit specifically columns headers separately. I found on the documentation that we can use ::first
, ::last
...
Is there any way to specify another section precisely (with something like [index = 3]
for example)?.
Upvotes: 1
Views: 4371
Reputation: 96
In some simple cases, you can change section colors of QHeaderView by using methods of a QAbstractItemModel and roles:
// text of 0-section will be red in header
m_model.setHeaderData(0, Qt::Horizontal, QBrush(Qt::red), Qt::ForegroundRole);
// background of a 25-section will be blue in header
m_model.setHeaderData(25, Qt::Horizontal, QBrush(Qt::blue), Qt::BackgroundRole);
Upvotes: 2
Reputation: 11555
No, there is no way to alter the appearance of a header section, with stylesheets, other than using ::first
, ::last
, ::middle
. The QStylesheetStyle
(the one used when a stylesheet is loaded) only implements those states.
To solve it you can basically either use a custom QHeaderView
that re-implements its paintEvent
, or, the option that I recommend you: to use a custom style (a QProxyStyle
is a good option, since it allows you to implement only the functionalities you want and inherit the rest from the base style). You have to re-implement the drawControl
method specifically for the CE_Header
element:
virtual void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const override {
if (element == CE_Header) { // sections
// ...
} else { // default behaviour for anything else
QProxyStyle::drawControl(element, option, painter, widget);
}
}
Now, the QStyleOptionHeader::section
variable contains the index of the section being painted, so you can use it to compute the color.
The full code of a minimum proxy style would be:
class MyProxyStyle : public QProxyStyle {
public:
MyProxyStyle(const QString& name) : // "fusion", "windows", ...
QProxyStyle(name) {
}
virtual void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const override {
if (element == CE_Header) {
auto ho = *qstyleoption_cast<const QStyleOptionHeader*>(option);
auto headerView = qobject_cast<const QHeaderView*>(widget);
ho.text = QString::number(ho.section); // for testing, it prints the section index
auto pal = ho.palette;
const QColor color(ho.section * 32 + 64, 0, 0); // color based on index
pal.setBrush(QPalette::All, QPalette::Button, color);
ho.palette = pal;
QProxyStyle::drawControl(element, &ho, painter, widget);
} else {
QProxyStyle::drawControl(element, option, painter, widget);
}
}
};
Note: I've managed to get it working with the fusion style only. It seems that the windows style implements it's own color scheme for headers. If you want to use such style then you should manually paint the header (within the same drawControl
, it is not necessary to re-implement the QHeaderView
).
To use the custom style just qApp->setStyle(new MyProxyStyle("fusion"));
(takes fusion as base style).
Result
VERY IMPORTANT NOTE: you must be aware that, as indicated in the documentation, you cannot use a custom QStyle
and a stylesheet at the same time yet:
Warning: Qt style sheets are currently not supported for custom QStyle subclasses. We plan to address this in some future release.
Previous answer
By mistake I previously answered the question for QTabBar
problem, which happens to be very similar: it is not possible to use a stylesheet to configure a given tab other than some pre-defined ones (first or last one, for example). We must either re-implement QTabBar
or use a custom style (as before). I'm keeping the solution for it just in case it is useful to somebody else.
The tricky part is that the style option doesn't have any information about the tab index, so you have to figure it out in some way. I find using the x
position of the tab (accessible from both the option and the QTabBar
) an efficient indicator to match tabs. If your tab bar is rendered vertically you should use the y
coordinate instead, and if the tab bar is multi-line, then use the whole rect
.
The full code of a minimum proxy style would be:
class MyProxyStyle : public QProxyStyle {
public:
MyProxyStyle(const QString& name) : // "fusion", "windows", ...
QProxyStyle(name) {
}
virtual void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const override {
if (element == CE_TabBarTab) {
auto to = *qstyleoption_cast<const QStyleOptionTab*>(option);
auto tabBar = qobject_cast<const QTabBar*>(widget);
for (int ii = 0; ii < tabBar->count(); ++ii) { // must find manually the tab
const auto rect = tabBar->tabRect(ii);
if (rect.x() == to.rect.x()) { // found the index of tab being painted
to.text = QString::number(ii); // for testing, it prints the tab index
auto pal = to.palette;
const QColor color(ii * 32 + 64, 0, 0); // color based on index
pal.setBrush(QPalette::All, QPalette::Button, color);
pal.setBrush(QPalette::All, QPalette::Background, color);
to.palette = pal;
break;
}
}
QProxyStyle::drawControl(element, &to, painter, widget);
} else {
QProxyStyle::drawControl(element, option, painter, widget);
}
}
};
The reason behind using different color roles when setting the brush comes from the fact that different style uses different roles when painting the section (fusion style uses QPalette::Button
for background, while windows uses QPalette::Background
instead). Other roles will allow you to tweak border and text colors, for example.
Results
With fusion style:
With windows style:
Upvotes: 5