简体   繁体   English

QTreeView::scrollTo 不工作

[英]QTreeView::scrollTo not working

Qt 4.8 Qt 4.8

I have a QTreeView based class with an asociated QAbstractItemModel based class.我有一个基于QTreeView的类和一个关联的基于QAbstractItemModel的类。 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.使用QTreeView::setSelectionModel(...)正确创建和连接两个类、树视图和模型,一切正常。

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:甚至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.

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.我刚刚处理了类似的情况,通过 setModelIndex(内部最终以 scrollTo 结束)设置模型索引对我的一个模型工作正常,但对另一个模型很糟糕。

When I forcefully expanded all level 1 items, the scrollTo worked just as described above (calling expandAll suffices).当我强制展开所有 1 级项目时,scrollTo 的工作方式与上述相同(调用expandAll就足够了)。

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.该错误是父模型索引的internalId与“从其他方向”计算相同模型索引(对于父)时不同,因此在此模型索引(由parent方法返回)无法在列表中找到视觉指标。

Everything was simple.一切都很简单。 Just change autoExpandDelay property from -1 to 0(for example).只需将 autoExpandDelay 属性从 -1 更改为 0(例如)。

ui->treeView->setAutoExpandDelay(0);

QTreeView::scrollTo should expand the hierarchy appropriately. QTreeView::scrollTo应该适当地扩展层次结构。

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).当模型更新时,您的QModelIndex对象可能会失效(并且可能仍在选择正确的行,因为行信息仍然有效,尽管父系不是,不要问我这些内部是如何工作的)。 From the QModelIndex documentation :QModelIndex文档

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 .如果您需要随着时间的推移保留模型索引,请使用QPersistentModelIndex

You can certainly look into the QPersistentModelIndex object, but like it says in its documentation :您当然可以查看QPersistentModelIndex对象,但就像它在其文档中所说的那样:

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.在我的情况下,row() 方法(应该返回其父项下索引的索引)没有正确实现。 Sadly QT doesnt complain about that, and even selects the index (if you expand manually you will notice).遗憾的是,QT 并没有抱怨,甚至选择了索引(如果您手动展开您会注意到)。 So, just go though the model code and hunt for bugs in row() and parent() methods etc.因此,只需浏览模型代码并寻找 row() 和 parent() 方法等中的错误。

You may be calling scrollTo before the tree view has finished reacting to the changes in current index and which indices are expanded/collapsed.您可能在树视图完成对当前索引的更改做出反应以及展开/折叠哪些索引之前调用scrollTo A possible solution may be to delay the call to scrollTo by connecting it to a single-shot timer like this:一个可能的解决方案可能是通过将它连接到这样的单次计时器来延迟对scrollTo的调用:

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

Using the timer will delay the call until control is passed back to the event queue.使用计时器将延迟调用,直到将控制权传递回事件队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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