Pregunta

Quiero ser capaz de expandir o contraer todos los niños de una rama particular en un QTreeView. Estoy usando PyQt4.

Yo sé que QTreeView a echar un expanda todos los niños cuentan que está obligado a *, pero necesito dos cosas: Se necesita ser unido a una combinación de teclas diferentes (cambio de espacio) y también tengo que ser capaz de colapsar todo los niños también.

Esto es lo que he probado hasta ahora: Tengo una subclase de un QTreeView que estoy comprobando para la combinación de teclas Shift-espacio. Sé que QModelIndex me deja escoger un niño específico con la función de "niño", pero que es necesario conocer el número de niños. I am capaz de obtener un recuento de los niños mirando el internalPointer, pero que sólo me da información para el primer nivel de la jerarquía. Si trato de usar la recursividad, puedo conseguir un montón de recuentos niño, pero entonces estoy perdido en cuanto a cómo obtener estos reconvertido en un QModelIndex válida.

Aquí hay un código:

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

Esto es el principio del método de recursión estaba investigando, pero se queda bloqueado cuando en realidad tratando de establecer el estado expandido, porque una vez dentro de la recursividad, pierdo "contacto" con cualquier QModelIndex válida ...

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

Gracias a todos por tomarse el tiempo para vistazo a esto!

¿Fue útil?

Solución

De acuerdo ... hermanos en realidad no me llegar a donde quería ir. Me las arreglé para conseguir el funcionamiento de código como sigue (y parece que una aplicación decente). Kudos todavía a Prof.Ebral que me va en el camino correcto con la idea de hermanos (resulta que necesitaba usar QModelIndex.child (fila, columna) e iterar recursivamente a partir de ahí).

Tenga en cuenta que existe la siguiente hipótesis en el código: Se asume que los objetos del almacén de datos subyacentes tienen la capacidad de informar el número de hijos que tienen (get_child_count () en mi código). Si ese no es el caso, tendrá alguna manera tiene que conseguir un recuento niño de manera diferente ... quizás arbitrariamente tratando de obtener índices niño - usando QModelIndex.child (fila, col) - con un cada vez mayor número de filas hasta que vuelvas un índice no válido? -. Esto es lo que sugiere Prof.Ebral y todavía podría tratar de que (es sólo que ya tengo una manera fácil de obtener el recuento menor solicitando lo de mi almacén de datos)

También tenga en cuenta que en realidad amplío / collpase cada nodo en un punto diferente en la recursividad en función de si estoy expandir o contraer. Esto se debe a que, a través de ensayo y error, he descubierto que las vistas de árbol animados tartamudearía y el pop si sólo lo hizo en un solo lugar en el código. Ahora, invirtiendo el orden en que lo hago en función de si estoy en el nivel superior (es decir, la raíz de la rama estoy afectando - no la raíz de toda la vista de árbol) consigo una bonita animación suave. Esto se documenta a continuación.

El código siguiente es en una subclase 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)

Otros consejos

model.rowCount (índice) es el método que desea.

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 (fila, col, padre) es esencialmente el mismo que llamar index.child (fila, col); simplemente con menos indirecciones.

Yo recomiendo usar un QTreeWidget que hereda QTreeView. A continuación, puede agarrar a los niños como QTreeWidgetItem.

Dado que usted no desea utilizar el QTreeWidget pero quiere meter a su modelo actual .. Se puede recorrer los 'posibles' niños usando, .isValid (). No se debe utilizar el internalPointer () sin embargo. En lugar de utilizar el cellItem que tiene, ya que es el ModalIndex originales .. luego tratar de encontrar su hermanos. Algo así como

x = 0; y =0
while cellIndex.sibling(x, y).isValid():
    child = cellIndex.sibling(x, y)
    x += 1
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top