Short answer: Stylesheets may not have the capability to achieve that functionality at this time. They are a relatively new feature in Qt and there seems to be a lack of ongoing development in this area.
Alternative options:
Stylesheets
Currently, it is not possible to assign properties to a column or item, nor can you access columns by index.
However, you can utilize pseudo-states selectors like :first
, :middle
, and :last
:
QTreeView::indicator:first:checked{
background: red;
}
QTreeView::indicator:middle:checked{
background: blue;
}
QTreeView::indicator:unchecked{
background: lightgray;
}
In this example, colors are used instead of images for simplicity. It should be noted that these pseudo-states are based on currently visible states, so changes in column order by the user can alter the styling. For instance, moving a :middle
column to the end would no longer display it as blue.
DecorationRole
You can simulate this behavior using Qt::DecorationRole
.
To achieve this, you need to capture the mousePressEvent
by subclassing QTreeView
or using an event filter. Then, you can change the icon (via Qt::DecorationRole
+ emit dataChanged()
) when the user clicks in the icon area.
Keep in mind that this method won't work with keyboard input.
Custom ItemDelegate
Create a subclass of QStyledItemDelegate
and override paint()
as you suggested.
Custom Style
For complex applications with heavy styling requirements, creating a custom Style may be necessary as stylesheets have limitations in certain aspects.
You can subclass QProxyStyle
, override drawPrimitive
, and handle the drawing for
QStyle::PE_IndicatorViewItemCheck
. The
QStyleOptionViewItem
provided contains properties like
checkState
,
features
(including
QStyleOptionViewItem::HasCheckIndicator
for checkboxes), and
index
for determining the checkbox's appearance.
Edit: Appendix
Example Using a Custom QStyledItemDelegate
void MyItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
QStyledItemDelegate::paint(painter, option, index);
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
const QWidget *widget = option.widget;
QStyle *style = widget ? widget->style() : QApplication::style();
QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget);
drawCheckBox(painter, checkRect, opt.checkState, index);
}
void MyItemDelegate::drawCheckBox(QPainter * painter, const QRect & checkRect, Qt::CheckState checkState, const QModelIndex & index) const
{
if (checkState == Qt::Checked)
{
switch (index.column())
{
case 0:
painter->fillRect(checkRect, Qt::red);
break;
default:
painter->fillRect(checkRect, Qt::blue);
}
}
else
{
painter->fillRect(checkRect, Qt::lightGray);
}
}
This example offers a straightforward solution by painting over the checkbox drawn by QStyledItemDelegate. It requires filling the entire box to avoid revealing the original checkbox.
Trying to use QStyledItemDelegate to draw everything except the checkbox, and then drawing the checkbox separately, is more challenging and may result in minor drawing artifacts if not implemented carefully.
Example Using a Custom QProxyStyle
void MyStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption * opt, QPainter * p, const QWidget * w) const
{
if (pe == QStyle::PE_IndicatorViewItemCheck)
{
const QStyleOptionViewItem * o = static_cast<const QStyleOptionViewItem *>(opt);
drawCheckBox(p, opt->rect, o->checkState, o->index);
return;
}
QProxyStyle::drawPrimitive(pe, opt, p, w);
}
The drawCheckBox()
method in this example is the same as in the previous example. This approach is simpler, cleaner, and avoids any drawbacks. The custom style can be applied globally or to specific widgets.