Search code examples
qtqtreeview

How to get last visible item in QTreeView


I have a QModelIndex of item in QTreeView.

How to test is this item is last visible item in QTreeView?

Fox example:

-item1 // expanded
--sub11
--sub12
-item2 // collapsed
--sub21

Function bool isItemVisible( QModelIndex idx ); should return true for item2, and false for sub21.

Note that rows may have different height.


Solution

  • Well, I have made the following sketch for the possible function that will tell you whether your item is the last one in the tree view hierarchy:

    The function itself:

    bool isItemVisible(QTreeView *view, const QModelIndex &testItem,
                       const QModelIndex &index)
    {
        QAbstractItemModel *model = view->model();
        int rowCount = model->rowCount(index);
        if (rowCount > 0) {
            // Find the last item in this level of hierarchy.
            QModelIndex lastIndex = model->index(rowCount - 1, 0, index);
            if (model->hasChildren(lastIndex) && view->isExpanded(lastIndex)) {
                // There is even deeper hierarchy. Drill down with recursion.
                return isItemVisible(view, testItem, lastIndex);
            } else  {
                // Test the last item in the tree.
                return (lastIndex == testItem);
            }    
        } else {
            return false;
        }    
    }
    

    How to use:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QTreeView view;
        MyModel model; // The QAbstractItemModel.
        view->setModel(&model);
    
        QModelIndex indexToTest = model.index(3, 0); // Top level item (4-th row).
        // Start testing from the top level nodes.
        bool result = isItemVisible(&view, indexToTest, QModelIndex());
    
        return a.exec();
    }
    

    Please note, that I haven't intensively tested this function, but I think it will work fine. You can, of course, improve it.

    UPDATE:

    After discussing the proposed method, I suggest the following solution that will decrease the number of function calls and improve overall performance.

    // Returns the last visible item in the tree view or invalid model index if not found any.
    QModelIndex lastVisibleItem(QTreeView *view, const QModelIndex &index = QModelIndex())
    {
        QAbstractItemModel *model = view->model();
        int rowCount = model->rowCount(index);
        if (rowCount > 0) {
            // Find the last item in this level of hierarchy.
            QModelIndex lastIndex = model->index(rowCount - 1, 0, index);
            if (model->hasChildren(lastIndex) && view->isExpanded(lastIndex)) {
                // There is even deeper hierarchy. Drill down with recursion.
                return lastVisibleItem(view, lastIndex);
            } else  {
                // Test the last item in the tree.
                return lastIndex;
            }    
        } else {
            return QModelIndex();
        }
    }
    

    Define a variable that will keep track of the last visible item in the tree. For example:

    static QModelIndex LastItem;
    

    Update the cached item each time the tree view items expanded or added/removed. This can be achieved in the slot that connected to QTreeView's expanded(), collapsed(), :rowsAboutToBeInserted, rowsAboutToBeRemoved() signals, i.e

    ..
    {
        LastItem = lastVisibleItem(tree);
    }
    

    Finally, to test a tree view item, just compare its model index with this LastItem without calling search function again.