(PyQt) QTreeView - хотите развернуть / свернуть всех детей и внуков - PullRequest
1 голос
/ 04 ноября 2010

Я хочу иметь возможность развернуть или свернуть все дочерние элементы определенной ветви в QTreeView. Я использую PyQt4.

Я знаю, что в QTreeView есть функция раскрытия всех дочерних элементов, связанная с *, но мне нужны две вещи: она должна быть связана с другой комбинацией клавиш (shift-space), и мне также нужно иметь возможность свернуть все а также дети.

Вот что я пробовал до сих пор: У меня есть подкласс QTreeView, в котором я проверяю комбинацию клавиш Shift-Space. Я знаю, что QModelIndex позволит мне выбрать конкретного дочернего элемента с помощью функции «child», но для этого необходимо знать количество дочерних элементов. Я могу получить счетчик детей, посмотрев на InternalPointer, но это дает мне информацию только для первого уровня иерархии. Если я попытаюсь использовать рекурсию, я могу получить кучу дочерних подсчетов, но потом я потеряюсь в том, как преобразовать их обратно в действительный QModelIndex.

Вот код:

def keyPressEvent(self, event):
    """
    Capture key press events to handle:
    - enable/disable
    """
    #shift - space means toggle expanded/collapsed for all children
    if (event.key() == QtCore.Qt.Key_Space and 
        event.modifiers() & QtCore.Qt.ShiftModifier):
        expanded = self.isExpanded(self.selectedIndexes()[0])
        for cellIndex in self.selectedIndexes():
            if cellIndex.column() == 0: #only need to call it once per row
                #I can get the actual object represented here
                item = cellIndex.internalPointer()
                #and I can get the number of children from that
                numChildren = item.get_child_count()
                #but now what? How do I convert this number into valid
                #QModelIndex objects? I know I could use: 
                #   cellIndex.child(row, 0)
                #to get the immediate children's QModelIndex's, but how
                #would I deal with grandchildren, great grandchildren, etc...
                self.setExpanded(cellIndex, not(expanded))
        return

Вот начало метода рекурсии, который я исследовал, но я застреваю при попытке установить расширенное состояние, потому что, оказавшись внутри рекурсии, я теряю «контакт» с любым действительным QModelIndex ...

def toggle_expanded(self, item, expand):
    """
    Toggles the children of item (recursively)
    """
    for row in range(0,item.get_child_count()):
        newItem = item.get_child_at_row(row)
        self.toggle_expanded(newItem, expand)
    #well... I'm stuck here because I'd like to toggle the expanded
    #setting of the "current" item, but I don't know how to convert
    #my pointer to the object represented in the tree view back into
    #a valid QModelIndex
    #self.setExpanded(?????, expand)   #<- What I'd like to run
    print "Setting", item.get_name(), "to", str(expand) #<- simple debug statement that indicates that the concept is valid

Спасибо всем, что нашли время взглянуть на это!

Ответы [ 3 ]

4 голосов
/ 17 ноября 2010

Хорошо ... братья и сестры на самом деле не привели меня туда, куда я хотел пойти.Мне удалось заставить код работать следующим образом (и это похоже на достойную реализацию).Спасибо профессору Эбралу, который заставил меня идти по правильному пути с идеей братьев и сестер (оказывается, мне нужно было использовать QModelIndex.child (строка, столбец) и рекурсивно выполнять итерацию оттуда).

Обратите внимание, что тамэто следующее предположение в коде: Предполагается, что ваши базовые объекты хранилища данных могут сообщать, сколько у них дочерних элементов (get_child_count () в моем коде).Если это не так, вам каким-то образом придется рассчитывать количество дочерних элементов по-другому ... возможно, просто произвольно пытаясь получить дочерние индексы - используя QModelIndex.child (row, col) - с постоянно увеличивающимся числом строк, пока не вернетесьневерный индекс?- это то, что предложил проф. Эбрал, и я все еще могу попробовать это (просто у меня уже есть простой способ подсчитать количество детей, запросив его из моего хранилища данных).

Также обратите внимание, что я на самом делеРазверните / сверните каждый узел в другой точке рекурсии в зависимости от того, развертываюсь ли я или сворачиваюсь.Это связано с тем, что методом проб и ошибок я обнаружил, что анимированные представления дерева будут заикаться и всплывать, если я просто сделаю это в одном месте кода.Теперь, меняя порядок, в котором я это делаю, основываясь на том, нахожусь ли я на верхнем уровне (то есть на корне ветви, на которую я воздействую, а не на корне всего дерева), я получаю приятную плавную анимацию.Это документировано ниже.

Следующий код находится в подклассе QTreeView.

#---------------------------------------------------------------------------
def keyPressEvent(self, event):

    if (event.key() == QtCore.Qt.Key_Space and self.currentIndex().column() == 0):
        shift = event.modifiers() & QtCore.Qt.ShiftModifier
        if shift:
            self.expand_all(self.currentIndex())
        else:                
            expand = not(self.isExpanded(self.currentIndex()))
            self.setExpanded(self.currentIndex(), expand)


#---------------------------------------------------------------------------
def expand_all(self, index):
    """
    Expands/collapses all the children and grandchildren etc. of index.
    """
    expand = not(self.isExpanded(index))
    if not expand: #if collapsing, do that first (wonky animation otherwise)
        self.setExpanded(index, expand)    
    childCount = index.internalPointer().get_child_count()
    self.recursive_expand(index, childCount, expand)
    if expand: #if expanding, do that last (wonky animation otherwise)
        self.setExpanded(index, expand)


#---------------------------------------------------------------------------
def recursive_expand(self, index, childCount, expand):
    """
    Recursively expands/collpases all the children of index.
    """
    for childNo in range(0, childCount):
        childIndex = index.child(childNo, 0)
        if expand: #if expanding, do that first (wonky animation otherwise)
            self.setExpanded(childIndex, expand)
        subChildCount = childIndex.internalPointer().get_child_count()
        if subChildCount > 0:
            self.recursive_expand(childIndex, subChildCount, expand)
        if not expand: #if collapsing, do it last (wonky animation otherwise)
            self.setExpanded(childIndex, expand)
2 голосов
/ 15 февраля 2011

model.rowCount (index) - это метод, который вам нужен.

model = index.model()   # or some other way of getting it
for i in xrange(model.rowCount(index)):
  child = model.index(i,0, index)
  # do something with child

model.index (row, col, parent) по сути аналогичен вызову index.child (row, col);просто с меньшим количеством косвенных указаний.

1 голос
/ 09 ноября 2010

Я бы рекомендовал использовать QTreeWidget, который наследует QTreeView. Затем вы можете получить детей как QTreeWidgetItem.

Поскольку вы не хотите использовать QTreeWidget, но хотите придерживаться своей текущей модели ... вы можете перебирать «возможных» потомков, используя .isValid (). Вы не должны использовать internalPointer (), хотя. Вместо этого используйте имеющийся у вас cellItem, так как он является оригинальным ModalIndex .., а затем попытайтесь найти его братьев и сестер. Что-то вроде

x = 0; y =0
while cellIndex.sibling(x, y).isValid():
    child = cellIndex.sibling(x, y)
    x += 1
...