QGIS stürzt ab, wenn ein Rollback durchgeführt wird, nachdem die Werte einer vom Benutzer hinzugefügten Funktion mit pyQGIS geändert wurden

8

Ich entwickle ein Addon für QGIS, das jedem Feature eine UUID zuweisen muss, sobald es der Ebene hinzugefügt wird. Ich verwende das Signal featureAdded, um die UUID in das entsprechende Feld des Features zu schreiben.

Dies ist der Code, den ich verwende (so vereinfacht wie möglich):

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

(Ich habe ein neues Plugin mit dem Add-On 'Plugin Builder' erstellt und das oben ist der einzige Code, den ich hinzugefügt habe .)

Sofern mir nichts fehlt, folgt dies den Richtlinien aus der Dokumentation im QGIS-Entwicklerkochbuch : http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with- ein-Bearbeitungspuffer

Wenn ich beim Bearbeiten der Ebene ein Feature hinzufüge, wird das Feld 'guid_pol' wie erwartet auf 'some_random_uuid' gesetzt. Ich kann die Änderungen jedoch problemlos festschreiben, wenn ich versuche, die Änderungen abzubrechen, anstatt sie festzuschreiben. QGIS stürzt mit dem Fehler 0xC0000005 (Zugriffsverletzung) ab .

Interessanterweise wird der Befehl 'Set UUID' nicht zum Undo / Redo-Stack hinzugefügt (zumindest nicht zum Undo / Redo-Panel ), und wenn ich versuche, ihn rückgängig zu machen , stürzt er ebenfalls ab .

Ich verwende QGIS 2.14, habe jedoch ein ähnliches Verhalten mit QGIS 2.12 beobachtet.

Es fällt mir schwer, das zum Laufen zu bringen. Gibt es etwas, was ich falsch mache?

mhm
quelle

Antworten:

5

Ich antworte mir :-) Ich habe eine Erklärung hier http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2

Derzeit ist es nicht sicher, Aufrufe durchzuführen, die Vektorebenendaten in Slots ändern, die mit Signalen verbunden sind, die über Datenänderungen benachrichtigt werden (z. B. featureAdded). Das Problem ist, dass zu dem Zeitpunkt, an dem diese Signale ausgegeben werden, die zugrunde liegenden Rückgängig-Befehle noch nicht auf den Stapel übertragen wurden. Wenn Sie also weitere Bearbeitungsaufrufe ausführen, wird der Rückgängig-Stapel beschädigt (der Rückgängig-Befehl für die Folgeoperation wird vor der ersten Operation platziert).

Meine Problemumgehung besteht darin, die Behandlung des Hinzufügens von Funktionen mithilfe des Slots editCommandEnded zu verzögern. Dies ist der relevante Code:

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

Ich hoffe das hilft jemand anderem.

mhm
quelle
3

mhm,

Ihre Antwort war wirklich großartig und hat unser Problem hier gelöst. Um jedoch vollständig zu verstehen, warum dies passiert ist, habe ich den QGIS-Quellcode und meinen Kollegen studiert und einen Artikel verfasst, in dem das Problem ausführlich erläutert wird. Bitte zögern Sie nicht, es zu überprüfen!

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

lcoandrade
quelle
1
Noch heute mit QGIS v3.4 war ich mit dem Problem konfrontiert und Ihr Beitrag gab mir eine Möglichkeit, es zu lösen. Vielen Dank, dass Sie dies gepostet haben! Übrigens, ich hatte Ihre Antwort bereits wie vor einem Jahr oder so positiv bewertet: D
Germán Carrillo