Как я могу эффективно расширить целое поддерево QTreeView? - PullRequest
1 голос
/ 15 февраля 2011

РЕДАКТИРОВАТЬ: выясняется, что проблема с производительностью root была связана с функцией размера, подходящей для сигнала расширенного (), поэтому я собираюсь принять первый ответ и удалить этот вопрос как вводящий в заблуждение.

Примечание: я задаю этот вопрос, чтобы я мог дать ответ на него (и, возможно, получить лучший ответ). Решение не интуитивно понятно.

Сборки MacOS для Qt могут дать пользователю возможность развернуть целое поддерево QTreeView (для него была открытая ошибка), но сборки без MacOS определенно этого не делают. Я пытаюсь реализовать поведение "нажатие клавиши" Shift "на украшении элемента расширяет все поддерево".

Есть две проблемы. Легче всего обнаружить сдвиг на декоре. Я делаю это, перехватывая расширенные / свернутые сигналы; они проверяют некоторое «глобальное» состояние, установленное 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 (). Однако API Qt не предоставляет метод expandSubtree (). Как это можно сделать быстро, если не копаться в частной реализации?

Ответы [ 4 ]

4 голосов
/ 15 февраля 2011

Нажатие клавиши «*» (звездочка) расширяет подузлы узла, и это именно то, что вам нужно. Вы пытались вызвать keyPressEvent с помощью ложного нажатия клавиши *

1 голос
/ 15 февраля 2011

Так как expandAll () быстрое, а развал (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)
0 голосов
/ 05 сентября 2017

Поскольку у меня возникла проблема с производительностью при попытке расширить поддеревья, и этот вопрос является первым результатом Google, я поделюсь своим мнением, хотя я использую C ++ и Qt5.

Решение TonyK с вызовомkeyPressEvent работает.Однако это решение показалось мне хакерским, поэтому я проверил источник Qt, и он действительно привязан к ключу Qt :: Key_Asterisk.(Прямо в QTreeView :: keyPressEvent, если вы хотите убедиться в этом сами.)

QTreeView :: keyPressEvent просто вызывает метод развертки (), в глубине, ничего особенного, никаких частных вызовов 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);
}
0 голосов
/ 12 апреля 2014
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);
  }
}
...