1

编辑:事实证明,根本性能问题是附加到扩展()信号的大小匹配函数,所以我将接受第一个答案并删除这个问题,因为它具有误导性。

注意:我问这个问题是为了提供答案(也许会得到更好的答案)。解决方案并不直观。

Qt 的 MacOS 构建可能有一种方法让用户扩展整个 QTreeView 子树(它有一个开放的错误),但非 MacOS 构建绝对没有。我正在尝试实现“在项目装饰上的 shift-click 扩展整个子树”的行为。

有两个问题。两者中较容易的是检测装饰上的 shift-click。我通过拦截展开/折叠的信号来做到这一点;他们检查 mousePressEvent 设置的一些“全局”状态:

# similar implementation for _on_expanded
@pyqtSlot(QModelIndex)
def _on_collapsed(self, index):
    if self._in_shift_press:
        self._in_shift_press = False
        _recursive_set_expanded(self, index, False)

def mousePressEvent(self, evt):
    # Make shift-click expand/collapse all
    if int(evt.modifiers() & Qt.ShiftModifier) != 0:
        self._in_shift_press = True
    try:
        QTreeView.mousePressEvent(self, evt)
    finally:
        self._in_shift_press = False

这有点难看,但效果很好。

更难的问题是实现 _recursive_set_expanded(view, root, state)。递归崩溃非常快。但是,在索引的所有后代上调用 view.setExpanded(True) 的明显实现非常慢——大约 100 个索引需要几秒钟。问题不在于昂贵的数据模型,因为 view.expandAll() 非常快。

一些资料显示,expandAll() 的工作量明显少于 expand()。但是,Qt API 没有公开 expandSubtree() 方法。如果不深入研究私有实现,如何才能快速做到这一点?

4

4 回答 4

4

按“*”(星号)键可展开节点的子节点,这正是您想要的。您是否尝试过使用假的“*”按键调用 keyPressEvent?

于 2011-02-15T07:44:36.240 回答
1

由于 expandAll() 很快,而 collapse(QModelIndex) 很快,我的解决方案是只使用这两种方法,避免调用 expand(QModelIndex):

def _recursive_set_expanded(view, root, desired):
    """For |root| and all its descendents, set the 'expanded' state to |desired|.
    It is undefined whether expanded and collapsed signals are emitted."""
    state = {}
    def _recursive_get_state(view, model, index, under_root):
        if index == root:
            under_root = True
        num_children = model.rowCount(index)
        if num_children:
            if under_root:
                state[index] = desired
            else:
                state[index] = view.isExpanded(index)
            for i in xrange(model.rowCount(index)):
                _recursive_get_state(view, model, model.index(i,0, index), under_root)

    _recursive_get_state(view, view.model(), QModelIndex(), False)
    view.expandAll()
    for k,v in state.iteritems():
        if not v:
            view.setExpanded(k, False)
于 2011-02-15T03:07:39.957 回答
0
void MainWindow::expandNode(const QModelIndex &parentIndex, bool expand) {
  tree->setExpanded(parentIndex, expand);
  for (qint32 rowNum = 0; rowNum < treeModel->rowCount(parentIndex); ++rowNum) {
    QModelIndex childIndex = treeModel->index(rowNum, 0, parentIndex);
    tree->setExpanded(childIndex, expand);
    expandNode(childIndex);
  }
}
于 2014-04-12T13:20:19.267 回答
0

由于我在尝试扩展子树时遇到了性能问题,而这个问题是谷歌的第一个结果,我将分享我的见解,尽管我使用的是 C++ 和 Qt5。

TonyK 调用 keyPressEvent 的解决方案有效。然而,这个解决方案对我来说感觉很笨拙,所以我检查了 Qt 源代码,它确实与 Qt::Key_Asterisk 键硬连线。(如果您想亲自查看,就在 QTreeView::keyPressEvent 中。)

QTreeView::keyPressEvent 只是以深度优先的方式调用 expand(),没什么特别的,没有私有 api 调用。当然,当我刚刚从 keyPressEvent 复制代码以便我的函数时,它起作用了:

QModelIndex current = currentIndex();
QStack<QModelIndex> parents;
parents.push(current);
QAbstractItemModel * mod = model();
while (!parents.isEmpty()) {
    QModelIndex parent = parents.pop();
    for (int row = 0; row < mod->rowCount(parent); ++row) {
        QModelIndex child = mod->index(row, 0, parent);
        if (!child.isValid())
            break;
        parents.push(child);
        expand(child);
    }
}
expand(current);

但是我想创建一个setExpandedRecursive(QModelIndex index, bool expanded)函数,所以我检查了它们与我的代码的区别,只是它们expand()最后而不是第一个调用子树的根节点。所以我在我的函数中也这样做了,你猜怎么着,现在问题是崩溃而不是扩展。所以这是我用于扩展折叠子树的最终解决方案:

void TreeViewClass::setExpandedRecursive(QModelIndex index, bool expanded)
{
    if (!index.isValid())
        return;

    const QAbstractItemModel * model = index.model();
    if (!expanded)
        setExpanded(index, expanded);
    for (int row = 0, count = model->rowCount(index); row < count; ++row)
        setExpandedRecursive(model->index(row, 0, index), expanded);
    if (expanded)
        setExpanded(index, expanded);
}
于 2017-09-05T08:57:28.587 回答