QGIS se bloquea al hacer una reversión después de modificar los valores de una característica agregada por el usuario con pyQGIS

8

Estoy desarrollando un complemento para QGIS que necesita asignar un UUID a cualquier característica tan pronto como se agregue a la capa. Estoy usando la señal featureAdded para escribir el UUID en el campo correspondiente de la función.

Este es el código que estoy usando (lo más simplificado posible):

def run(self):
    self.iface.mapCanvas().currentLayer().featureAdded.connect(self.onFeatureAdded)

def onFeatureAdded(self, fid):
    layer = self.iface.mapCanvas().currentLayer()
    layer.beginEditCommand("Set UUID")
    print layer.changeAttributeValue(fid, layer.fieldNameIndex('guid_pol'), 'some_random_uuid') # prints True
    layer.endEditCommand()

(Creé un nuevo complemento con el complemento 'Creador de complementos' y el anterior es el único código que le he agregado ).

A menos que me falte algo, esto sigue las pautas de la documentación en el libro de cocina para desarrolladores de QGIS : http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with- un búfer de edición

Cuando edito la capa, si agrego una característica, el campo 'guid_pol' se establece en 'some_random_uuid' como se esperaba. Sin embargo, puedo confirmar los cambios sin problemas si, en lugar de confirmarlos, intento cancelarlos QGIS falla con el error 0xC0000005 (Infracción de acceso) .

Curiosamente, el comando 'Establecer UUID' no se agrega a la pila de deshacer / rehacer (al menos, no al panel Deshacer / rehacer ) y si intento deshacerlo también se bloquea .

Estoy usando QGIS 2.14 pero observé un comportamiento similar con QGIS 2.12.

Me está costando que esto funcione. ¿Hay algo que estoy haciendo mal?

mhm
fuente

Respuestas:

5

Me respondo :-) He encontrado una explicación aquí http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2

Actualmente, no es seguro hacer llamadas que modifiquen los datos de la capa vectorial en las ranuras conectadas a las señales que notifican el cambio de datos (como featureAdded). El problema es que en el momento en que se emiten esas señales, sus comandos de deshacer subyacentes aún no se introdujeron en la pila, por lo que realizar más llamadas de edición provoca la corrupción de la pila de deshacer (el comando de deshacer para la operación de seguimiento se coloca antes de la primera operación).

Mi solución consiste en retrasar el manejo de la adición de características usando el slot editCommandEnded. Este es el código relevante:

def onFeatureAdded(self, fid):
    if fid < 0:
        self._addedFeatures.append(fid)

def onEditCommandEnded(self):
    while self._addedFeatures:
        fid = self._addedFeatures.pop()
        self._handleAdded(fid)

def _handleAdded(self, fid):
    guid_pol = str(uuid4()) # RFC 4122 UUID v4
    try:
        self.layer.beginEditCommand(u"Assign UUID")
        self.layer.changeAttributeValue(fid, self.layer.fieldNameIndex('guid_pol'), guid_pol)
        self.layer.endEditCommand()
    except:
        self.layer.destroyEditCommand()
        raise

Espero que esto ayude a alguien más.

mhm
fuente
3

mhm

Su respuesta fue realmente genial y resolvió nuestro problema aquí. Pero para comprender completamente por qué sucedió esto, cómo resolverlo, estudié el código fuente de QGIS y mi compañero de trabajo, e hice un artículo explicando el problema en detalle. ¡Por favor, siéntase libre de revisarlo!

https://gis4programmers.wordpress.com/2017/02/26/working-properly-with-pyqgqis-edit-buffer-to-enable-undo-commands/

lcoandrade
fuente
1
Incluso hoy con QGIS v3.4 me enfrenté al problema y su publicación me dio una forma de resolverlo, ¡gracias por publicar esto! Por cierto, ya había votado tu respuesta, como hace un año más o menos: D
Germán Carrillo