Drawing QTreeView items with QStyledItemDelegate

2.5k views Asked by At

I have created a project based on the Simple Tree Model Example from the Qt examples list and edited its model so that some items can also be checked; this is how it looks like:

enter image description here

I would like some of the items to be slightly moved to the left. So I created a delegate by deriving QStyledItemDelegate and reimplemented QStyledItemDelegate::paint like this:

void TreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.column() == 0) {
        TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
        if (childItem->type() == TreeItem::Type::Checkable) {
            QStyleOptionViewItem opt = option;
            QStyledItemDelegate::initStyleOption(&opt, index);

            const int desiredThreshold = 10;

            opt.rect.setX(opt.rect.x() - desiredThreshold);
            option.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget);

            return;
        }
    }

    return QStyledItemDelegate::paint(painter, option, index);
}

This way items of type TreeItem::Type::Checkable will be drawn to the left by the value of the desiredThreshold constant (in this case 10 pixels).

So far so good; everything works well and the drawing is done correctly. However...

The problem is that although the item is drawn slightly to the left(which is ok), the mouse events are still working as if the item didn't move at all; here's how it works:

enter image description here

Is it possible to tell the delegate that the whole item is drawn slightly to the left so that when I click on the checkbox(which was also moved together with the whole item) the model would be correctly updated?

1

There are 1 answers

0
scopchanov On BEST ANSWER

Cause

You change how the ItemViewItem is rendered on the screen, but not how it responds to user actions.

Solution

I would suggest you to reimplement QStyledItemDelegate::editorEvent; in order to adjust the position of the QRect returned by QStyle::subElementRect when called with QStyle::SE_ItemViewItemCheckIndicator as an argument.

Example

Consider the following steps:

  1. Add a public editorEvent method in your TreeItemDelegate class
  2. Copy the default implementation of QStyledItemDelegate::editorEvent into your code
  3. Avoid the call to the private method of QStyledItemDelegate by changing

    const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
    QStyle *style = widget ? widget->style() : QApplication::style();
    

    to

    QStyle *style = option.widget->style();
    
  4. Adjust the position of checkRect by changing

    QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
    

    to

    QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, option.widget).adjusted(-10, 0, -10, 0);