简体   繁体   中英

QTreeView::scrollTo not working

Qt 4.8

I have a QTreeView based class with an asociated QAbstractItemModel based class. If I reload the model with new information I want to expand/scroll the tree to a previous selected item.

Both clases, tree view and model are correctly created and connected using QTreeView::setSelectionModel(...) working everything properly.

After reloading the model, I get a valid index to the previous selected item and I scrollTo it:

myTreeView->scrollTo(index);

but the tree is not expanded. However, if I expand the tree manually, the item is really selected.

Tree view is initialized in contruct with:

header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
header()->setStretchLastSection(false);
header()->setResizeMode(0, QHeaderView::ResizeToContents);

Any idea about expanding the tree to the selection?

Even QTreeView::scrollTo documentation says:

Scroll the contents of the tree view until the given model item index is 
visible. The hint parameter specifies more precisely where the item should 
be located after the operation. If any of the parents of the model item 
are collapsed, they will be expanded to ensure that the model item is visible.

That is not really true (I think)

If solved the problem expanding all previous tree levels manually:

// This slot is invoqued from model using last selected item
void MyTreeWidget::ItemSelectedManually(const QModelIndex & ar_index)
{
    std::vector<std::pair<int, int> > indexes;

    // first of all, I save all item "offsets" relative to its parent

    QModelIndex indexAbobe = ar_index.parent();
    while (indexAbobe.isValid())
    {
        indexes.push_back(std::make_pair(indexAbobe.row(), indexAbobe.column()));
        indexAbobe = indexAbobe.parent();
    }

    // now, select actual selection model

    auto model = _viewer.selectionModel()->model();

    // get root item

    QModelIndex index = model->index(0, 0, QModelIndex());
    if (index.isValid())
    {
        // now, expand all items below

        for (auto it = indexes.rbegin(); it != indexes.rend() && index.isValid(); ++it)
        {
            auto row = (*it).first;
            auto colum = (*it).second;

            _viewer.setExpanded(index, true);

            // and get a new item relative to parent
            index = model->index(row, colum, index);
        }
    }

    // finally, scroll to real item, after expanding everything above.
    _viewer.scrollTo(ar_index);
}

I just dealt with similar situation, setting model index via setModelIndex (which internally ends up with scrollTo) worked OK for one of my models, but badly for the other one.

When I forcefully expanded all level 1 items, the scrollTo worked just as described above (calling expandAll suffices).

The reason was a bug in my model class in:

QModelIndex MyBadModel::parent(const QModelIndex& index) const

and as I fixed that, things got normal there too. The bug was such that internalId of parent model index was not the same as when this same model index (for parent) is calculated "from other direction", therefore in this model index (returned by parent method) could not be found in the list of visual indices.

Everything was simple. Just change autoExpandDelay property from -1 to 0(for example).

ui->treeView->setAutoExpandDelay(0);

QTreeView::scrollTo should expand the hierarchy appropriately.

It's likely that your QModelIndex object is being invalidated when the model is updated (and perhaps still selecting the correct row because the row information is still valid though the parentage is not, don't ask me how those internals work). From the QModelIndex documentation :

Note: Model indexes should be used immediately and then discarded. You should not rely on indexes to remain valid after calling model functions that change the structure of the model or delete items. If you need to keep a model index over time use a QPersistentModelIndex .

You can certainly look into the QPersistentModelIndex object, but like it says in its documentation :

It is good practice to check that persistent model indexes are valid before using them.

Otherwise, you can always query for that item again after the model refresh.

Recently I struggled with same problem. It's most likely a bug in your model class implementation. in my case the row() method (that supposed to return index of the index under its parent) was not implemented correctly. Sadly QT doesnt complain about that, and even selects the index (if you expand manually you will notice). So, just go though the model code and hunt for bugs in row() and parent() methods etc.

You may be calling scrollTo before the tree view has finished reacting to the changes in current index and which indices are expanded/collapsed. A possible solution may be to delay the call to scrollTo by connecting it to a single-shot timer like this:

QTimer::singleShot(0, [this]{scrollTo(index);});

Using the timer will delay the call until control is passed back to the event queue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM