QTreeView::scrollTo 不起作用

QTreeView::scrollTo not working

本文关键字:不起作用 scrollTo QTreeView      更新时间:2023-10-16

Qt 4.8

我有一个基于 QTreeView 的类和一个关联的基于QAbstractItemModel的类。如果我用新信息重新加载模型,我想将树展开/滚动到上一个选定的项目。

使用QTreeView::setSelectionModel(...)正确创建和连接所有组件,树视图和模型都正确创建和连接。

重新加载模型后,我获得了上一个选定项目的有效索引,然后滚动到它:

myTreeView->scrollTo(index);

但是树没有展开。但是,如果我手动展开树,则确实选择了该项目。

树视图在构造中初始化为:

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

关于将树扩展到选择的任何想法?

甚至QTreeView::scrollTo文档也说:

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.

这不是真的(我认为(

如果解决了手动扩展所有先前树级别的问题:

// 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);
}

我刚刚处理了类似的情况,通过setModelIndex(内部以scrollTo结束(设置模型索引对于我的一个模型来说效果很好,但对另一个模型来说很糟糕。

当我强行扩展所有 1 级项目时,scrollTo 的工作方式如上所述(调用expandAll就足够了(。

原因是我的模型类中的一个错误:

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

当我解决这个问题时,那里的事情也变得正常了。该错误使得父模型索引的internalId与"从其他方向"计算同一模型索引(对于父模型(时不同,因此在此模型中索引(由parent方法返回(无法在可视索引列表中找到。

一切都很简单。只需将 autoExpandDelay 属性从 -1 更改为 0(例如(。

ui->treeView->setAutoExpandDelay(0);

QTreeView::scrollTo应该适当地扩展层次结构。

更新

模型时,您的QModelIndex对象很可能已失效(并且可能仍在选择正确的行,因为行信息仍然有效,尽管父项不是,请不要问我这些内部是如何工作的(。 从QModelIndex文档中:

注意:模型索引应立即使用,然后丢弃。在调用更改模型结构或删除项的模型函数后,不应依赖索引来保持有效。如果需要随时间推移保留模型索引,请使用 QPersistentModelIndex。

您当然可以查看QPersistentModelIndex对象,但就像它在其文档中所说的那样:

在使用持久模型索引之前,最好先检查它们是否有效。

否则,您始终可以在模型刷新后再次查询该项。

最近我遇到了同样的问题。这很可能是模型类实现中的错误。在我的情况下,row(( 方法(应该返回其父级索引下的索引(没有正确实现。可悲的是,QT并没有抱怨这一点,甚至选择了索引(如果你手动展开,你会注意到(。因此,只需浏览模型代码并寻找row((和parent((方法等中的错误。

在树视图完成对当前索引的更改以及展开/折叠哪些索引的反应之前,您可能会调用scrollTo。一个可能的解决方案可能是通过将调用连接到单次计时器来延迟对scrollTo的调用,如下所示:

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

使用计时器将延迟调用,直到将控制权传递回事件队列。