QGIS se bloque lors d'une restauration après avoir modifié les valeurs d'une fonctionnalité ajoutée par l'utilisateur avec pyQGIS

8

Je développe un module complémentaire pour QGIS qui doit attribuer un UUID à n'importe quelle fonctionnalité dès qu'il est ajouté à la couche. J'utilise le signal featureAdded pour écrire l'UUID dans le champ correspondant de la fonctionnalité.

Voici le code que j'utilise (aussi simplifié que possible):

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()

(J'ai créé un nouveau plugin avec le module complémentaire 'Plugin Builder' et c'est ci-dessus le seul code que je lui ai ajouté .)

À moins que je manque quelque chose, cela suit les directives de la documentation dans le livre de cuisine du développeur QGIS : http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with- un-tampon-d'édition

Lorsque j'édite le calque, si j'ajoute une fonction, le champ 'guid_pol' est réglé sur 'some_random_uuid' comme prévu. Cependant, je peux valider les modifications sans problème si, au lieu de valider les modifications, j'essaie de les annuler QGIS se bloque avec l'erreur 0xC0000005 (violation d'accès) .

Fait intéressant, la commande «Définir l'UUID» n'est pas ajoutée à la pile d'annulation / de rétablissement (du moins, pas au panneau Annuler / Rétablir ) et si j'essaye de l'annuler, elle se bloque également .

J'utilise QGIS 2.14 mais j'ai observé un comportement similaire avec QGIS 2.12.

J'ai du mal à faire fonctionner ça. Y a-t-il quelque chose que je fais mal?

mhm
la source

Réponses:

5

Je me réponds :-) J'ai trouvé une explication ici http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2

Actuellement, il n'est pas sûr de faire des appels qui modifient des données de couche vectorielle dans des emplacements connectés à des signaux notifiant un changement de données (comme featureAdded). Le problème est qu'au moment où ces signaux sont émis, leurs commandes d'annulation sous-jacentes n'étaient pas encore poussées dans la pile, donc effectuer d'autres appels d'édition entraîne la corruption de la pile d'annulation (la commande d'annulation pour l'opération de suivi est placée avant la première opération).

Ma solution consiste à retarder la gestion de l'ajout de fonctionnalités à l'aide de l'emplacement editCommandEnded. Voici le code pertinent:

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

J'espère que cela aide quelqu'un d'autre.

mhm
la source
3

mhm,

Votre réponse était vraiment géniale et a résolu notre problème ici. Mais pour bien comprendre pourquoi cela s'est produit et comment le résoudre, j'ai étudié le code source de QGIS et mon collègue et j'ai fait un article expliquant le problème en détail. N'hésitez pas à le vérifier!

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

lcoandrade
la source
1
Aujourd'hui encore, avec QGIS v3.4, j'ai rencontré le problème et votre message m'a donné un moyen de le résoudre, merci d'avoir posté cela! BTW, j'avais déjà voté pour votre réponse, comme il y a un an environ: D
Germán Carrillo