How to style QTreeView items by role with CSS ?
-
Hello,
I have a QTreeView and a custom model in an application which uses a custom CSS stylesheet.
I want to color some items in my tree view depending on their Qt::ForegroundRole, which returns a non-null color in some specific cases.
However it seems CSS overrides this and my items don't change color.So I wondered if it's possible, like in HTML, to put "CSS classes" on items so I can style them directly in CSS for the special cases my application defines. But I have no clue how to do that, especially with model-view system...
So I tried QStyledItemDelegate, but again I don't find many examples about how to do this simple thing.
I have this so far:void TextColorDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex &index) const { QVariant d = index.data(Qt::ForegroundRole); if (d.type() != QVariant::Color) QStyledItemDelegate::paint(painter, option, index); else { QColor color = d.value<QColor>(); QBrush brush = painter->brush(); brush.setColor(color); painter->setBrush(brush); QString text = index.data(Qt::DisplayRole).toString(); painter->drawText(option.rect, 0, text); } }
But all it does is draw a black text with fixed background even when selected, hovered etc.
Any ideas? -
@Zylann
it's not possible to style items in itemview widgets individually by Qt.The only solution is:
- add a string property to your tree view
- define a simple syntax to define the font colors for your data role values
- in the property setter parse the string and set it to the item delegate
- subclass initStyleOption() in the delegate (see bleow)
virtual void MyItemDelegate::initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index) const { QStyledItemDelegate::initStyleOption(option, index); if( index.data( MY_ITEM_DATA_ROLE ) == ??? ) { QPalette::ColorGroup cg = option->state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if( cg == QPalette::Normal && !(option->state & QStyle::State_Active) ) cg = QPalette::Inactive; QColor fontColor = ....; option->palette.setColor(cg, option->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text, fontColor); } }
-
@SGaist Yes, theoretically the correct way for the designer would be the ability to wrote something like:
QTreeView::item:mycustomstate { color: #abc; }
But at the moment, if I could just get the color to change according to Qt::ForegroundRole, it would be a good start too.
@raven-worx My model can already return a color when I query data(Qt::ForegroundRole).
I modified my column delegate so it overrides initStyleOption() like you did, but it has no effect.
What do you mean by adding a string property to the tree view? Subclass QTreeView? What would be this property for? -
@Zylann
The property was for styling via stylesheets.
But now you say that the color comes from the model.Please show your initStyleOption() implementation.
-
void TextColorDelegate::initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index) const { QStyledItemDelegate::initStyleOption(option, index); QVariant d = index.data(Qt::ForegroundRole); if (d.type() == QVariant::Color) { QColor color = d.value<QColor>(); QPalette::ColorGroup cg = option->state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option->state & QStyle::State_Active)) { cg = QPalette::Inactive; } option->palette.setColor(cg, option->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text, color); } }
I tried again without CSS, I get colors. With CSS, no colors but those from CSS.
I also realized I was setting the proxy before the model to be set, so now I set it after, but that didn't fixed the problem. -
@Zylann
are you sure you are successfully passing the condition d.type() == QVariant::Color?
Because i am almost sure the code works :)
Also the ForegroundRole would be used already by Qt when you remove the stylesheet. -
Everything is fine and works when I remove the CSS. But with CSS, I don't get that because the style overrides my code.
I even tried to remove the if and hardcode QColor(0,255,0) for every case, with no luck.
The only time I got something look "different" is by overriding paint() (see my first post), but it also broke many other things, not only the text color. -
I finally managed to get custom colors. I gave my QTreeView an object name to be able to write this in CSS:
m_treeView->setObjectName("MyTreeView"); m_treeView->setStyleSheet("QTreeView#MyTreeView::item {color: none;}");
basically now my model controls text color through Qt::ForegroundRole regardless of the application's CSS.
I feel like it's the wrong place to put theming, but it works for me at the moment.
Well... until we decide to have different themes :-°