QTreeView indent entire row



  • I am using a QTreeView with a custom QAbstractItemModel. My items can have children. If an item has one or more children, the tree view automatically indents the item of of the first column of the row.
    What is the correct way to make the view indent the entire row? I'd like that each item of that row (so each column so to speak) gets additional indentation relative to the parent item.

    Screenshot for reference:
    I'd like that the items of the columns Priority and Description are indented as well.


  • Moderators

    I don't think there's a built-in way to do that, but you can use a QStyledItemDelegate derived item delegate with paint method like this:

    void MyCustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
    {
        //if it's column 0 just draw the original
        if (index.column() == 0)
        {
            QStyledItemDelegate::paint(painter, option, index);
            return;
        }
    
        //get the style to draw with
        QStyle* style = option.widget ? option.widget->style() : QApplication::style();
    
        //calculate tree level
        int level = 0;
        for(auto i = index; (i = i.parent()).isValid(); level++);
    
        //calculate indentation
        auto view = qobject_cast<const QTreeView*>(option.widget);
        int indent = level * (view ? view->indentation() : 20 ); //some arbitrary default value
    
        //create a styled option object
        QStyleOptionViewItem opt = option;
        QStyledItemDelegate::initStyleOption(&opt, index);
    
        //draw indented item
        opt.rect.adjust(indent, 0, 0, 0);
        style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget);
    
        //fill the gap space
        opt.rect = option.rect;
        opt.rect.setWidth(indent);
        opt.text.clear(); //remove text
        opt.viewItemPosition = QStyleOptionViewItem::Middle; //remove selection frame sides
        style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget);
    }
    


  • I'm not sure how to thank you for this. Your code works out of the box. Nothing left for me to do :D

    The only question I have is: Can I use this new IndentationDelegate together with my own custom delegates? I see that your code ultimately uses the default delegates. How can I make this work with my own delegates?

        _myTree->setItemDelegateForColumn(1, new PriorityComboboxDelegate(_todoItemsManager));
        _myTree->setItemDelegateForColumn(1, new IndentationItemDelegate);
    

    I know that this can't work that way. It's just to illustrate what I want to be doing. I'd like the IndentationDelegate to be able to use my own custom delegate and just add indentation like it currently works with the "built-in" delegates.

    Thank you very much, I appreciate it a lot!


  • Moderators

    @Joel-Bodenmann said:

    How can I make this work with my own delegates?

    each index can max only have 1 delegate. Thus you need to merge the code into your own delegate.
    Since you also receive a QModelIndex in the most methods of the delegate you need to check the column there.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.