O QGIS trava ao fazer uma reversão após modificar valores de um recurso adicionado pelo usuário com pyQGIS

8

Estou desenvolvendo um complemento para o QGIS que precisa atribuir um UUID a qualquer recurso assim que ele for adicionado à camada. Estou usando o sinal featureAdded para escrever o UUID no campo correspondente do recurso.

Este é o código que estou usando (o mais simplificado possível):

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

(Criei um novo plug-in com o complemento 'Plugin Builder' e o código acima é o único que adicionei a ele .)

A menos que esteja faltando alguma coisa, siga as diretrizes da documentação do livro de receitas do desenvolvedor do QGIS : http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with- um buffer de edição

Quando edito a camada, se adicionar um recurso, o campo 'guid_pol' será definido como 'some_random_uuid' conforme o esperado. No entanto, posso confirmar as alterações sem problemas. Se, ao invés de confirmar as alterações, eu tentar cancelá-las, o QGIS trava com o erro 0xC0000005 (Violação de Acesso) .

Curiosamente, o comando 'Set UUID' não é adicionado à pilha de desfazer / refazer (pelo menos, não ao painel Desfazer / refazer ) e se eu tentar desfazer, ele também trava .

Estou usando o QGIS 2.14, mas observei um comportamento semelhante ao QGIS 2.12.

Estou tendo dificuldades para fazer isso funcionar. Existe algo que estou fazendo de errado?

mhm
fonte

Respostas:

5

Respondo a mim mesmo :-) Encontrei uma explicação aqui http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2

Atualmente, não é seguro fazer chamadas que modifiquem os dados da camada vetorial nos slots conectados aos sinais que notificam a alteração dos dados (como featureAdded). O problema é que, no momento em que esses sinais são emitidos, seus comandos de desfazer subjacentes ainda não foram enviados à pilha, portanto, fazer chamadas de edição adicionais causa corrupção na pilha de desfazer (o comando desfazer para a operação de acompanhamento é colocado antes da primeira operação).

Minha solução alternativa consiste em atrasar o tratamento da adição de recurso usando o slot editCommandEnded. Este é o 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 isso ajude outra pessoa.

mhm
fonte
3

mhm,

Sua resposta foi realmente ótima e resolveu nosso problema aqui. Mas, para entender completamente por que isso aconteceu, como resolvê-lo, estudei o código-fonte do QGIS e meu colega de trabalho e fiz um artigo explicando o problema em detalhes. Por favor, fique à vontade para conferir!

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

lcoandrade
fonte
1
Ainda hoje, com o QGIS v3.4, eu enfrentei o problema e sua postagem me deu uma maneira de resolvê-lo, obrigado por postar isso! BTW, eu já tinha votado na sua resposta, há mais ou menos um ano: D
Germán Carrillo