Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Get geometry of a row in QTreeView



  • I want to be able to make an editor in my custom delegate span all columns on demand. I'm trying to do it with a subclassed QStyledItemDelegate and QTreeView as follows:

        // Subclassed QTreeView
        QRect rowGeometry(const QModelIndex &index) {
            int indent = (index.column() + 1) * indentation();
            int firstSection = header()->logicalIndex(0);
            int lastSection = header()->logicalIndex(header()->count() - 1);
            int left = header()->sectionViewportPosition(firstSection);
            int right = header()->sectionViewportPosition(lastSection) + header()->sectionSize(lastSection);
    
            left += indent;
    
            QPoint rowTopLeft(rect().topLeft().x() + indent, rect().topLeft().y() + rowHeight(index) * (index.row() + 1);
            QRect rec(rect().topLeft(), QSize(right - left, rowHeight(index)));
            return rec;
        }
    
        // Subclassed QStyledItemDelegate
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
            editor->setGeometry(m_subclassedTreeView->rowGeometry(index));
        }
    

    The result is that the editor doesn't follow the indentation, and is always on row 0. I'm also open to accomplishing this some other way.


  • Lifetime Qt Champion

    Hi,

    Can you provide a minimal compilable example that shows that behaviour ?



  • #include <QTreeView>
    #include <QHeaderView>
    #include <QStyledItemDelegate>
    #include <QStandardItemModel>
    #include <QVBoxLayout>
    
    class ExpandableTreeView : public QTreeView {
    public:
        ExpandableTreeView(QWidget *parent = nullptr) : QTreeView(parent) {
        }
        void setExpandableIndex(const QModelIndex &index) {m_expandableIndex = index;}
        QRect rowGeometry(const QModelIndex &index) {
            int indent = (index.column() + 1) * indentation();
            int firstSection = header()->logicalIndex(0);
            int lastSection = header()->logicalIndex(header()->count() - 1);
            int left = header()->sectionViewportPosition(firstSection);
            int right = header()->sectionViewportPosition(lastSection) + header()->sectionSize(lastSection);
    
            left += indent;
    
            QPoint rowTopLeft(rect().topLeft().x() + indent, rect().topLeft().y() + rowHeight(index));
            QRect rec(rect().topLeft(), QSize(right - left, rowHeight(index)));
            return rec;
        }
    private:
        QModelIndex m_expandableIndex;
    };
    
    class ExpandableDelegate : public QStyledItemDelegate {
    public:
        ExpandableDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
            return QStyledItemDelegate::sizeHint(option, index);
        }
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
            QRect geo = m_eview->rowGeometry(index);
            editor->setGeometry(geo);
        }
        void setExpandableIndex(const QModelIndex &index) {m_expandableIndex = index;}
        void setExpandableTreeView(ExpandableTreeView *view) {m_eview = view;}
    private:
        QModelIndex m_expandableIndex;
        ExpandableTreeView *m_eview;
    };
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        auto central = new QWidget;
    
        auto lo = new QVBoxLayout;
    
        auto model = new QStandardItemModel;
    
        auto root = model->invisibleRootItem();
    
        auto view = new ExpandableTreeView;
    
        QList <QStandardItem*> rowItems;
        for (int i = 0; i < 3; i++) {
            auto item = new QStandardItem;
            item->setText(QString::number(i));
            rowItems.append(item);
    
            auto i2 = new QStandardItem;
            i2->setText(QString::number(i + 1));
            rowItems.append(i2);
    
    
            root->appendRow(rowItems);
            rowItems.clear();
        }
        auto delegate = new ExpandableDelegate;
        delegate->setExpandableTreeView(view);
    
        view->setItemDelegate(delegate);
        view->setModel(model);
    
        lo->addWidget(view);
    
        central->setLayout(lo);
    
        setCentralWidget(central);
    
        connect(view, &ExpandableTreeView::activated, [=](const QModelIndex &index) {
            delegate->setExpandableIndex(index);
        });
    }
    


  • I think this could be easily solved by just using visualRect() in the delegate:

    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &, const QModelIndex &index) const {
        const int maxCol = index.model()->columnCount(index.parent());
        QRect tempRect = m_subclassedTreeView->visualRect(index.model()->index(index.row(),0,index.parent()));
        int top = tempRect.top();
        int left = tempRect.left();
        int bottom = tempRect.bottom();
        int right= tempRect.right();
        for(int i = 1;i<maxCol ;++i){
            tempRect =m_subclassedTreeView->visualRect(index.model()->index(index.row(),i,index.parent()));
            if(tempRect.top()<top)
                top = tempRect.top();
            if(Q_UNLIKELY(tempRect.left()<left))
                left= tempRect.left();
            if(tempRect.bottom()>bottom)
                bottom = tempRect.bottom();
            if(Q_LIKELY(tempRect.right()>right))
                right= tempRect.right();
        }
        editor->setGeometry(QRect(QPoint(top,left),QPoint(bottom,right)));
    }
    


  • @VRonin That works though I had to change editor->setGeometry(QRect(QPoint(top, left),QPoint(bottom, right))); to editor->setGeometry(QRect(QPoint(left, top),QPoint(right, bottom)));


Log in to reply