pyQGISでユーザーが追加したフィーチャの値を変更した後にロールバックを実行すると、QGISがクラッシュします


8

レイヤーに追加されたらすぐにUUIDをフィーチャに割り当てる必要があるQGISのアドオンを開発しています。featureAdded信号を使用して、機能の対応するフィールドにUUIDを書き込みます。

これは私が使用しているコードです(可能な限り簡略化しています):

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

(私は 'Plugin Builder'アドオンで新しいプラグインを作成しました、そしてそれは私がそれに追加した唯一のコードです。)

私は何かが欠けていない限り、これは中のドキュメントからのガイドライン次のQGISの開発者の料理をhttp://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with-編集バッファー

レイヤーを編集するときに、フィーチャを追加すると、フィールド「guid_pol」が期待どおり「some_random_uuid」に設定されます。問題なく変更をコミットできますが、変更をコミットする代わりにキャンセルしようとすると、エラー0xC0000005(アクセス違反)でQGISがクラッシュします

興味深いことに、「Set UUID」コマンドは元に戻す/やり直しスタックに追加されません(少なくとも、元に戻す/やり直しパネルには追加されません)。また、に戻そうとするとクラッシュします

QGIS 2.14を使用していますが、QGIS 2.12でも同様の動作が見られました。

これを機能させるのに苦労しています。私が間違っていることはありますか?

回答:


5

私は自分に答えます:-)ここで説明を見つけました http://qgis-developer.osgeo.narkive.com/5wnziigA/wrapping-changeattributevalue-between-begin-and-end-editcommand#post2

現在、データの変更について通知する信号(featureAddedなど)に接続されたスロットのベクターレイヤーデータを変更する呼び出しを行うことは安全ではありません。問題は、これらの信号が発行された時点で、それらの基本的な取り消しコマンドがまだスタックにプッシュされていないため、さらに編集呼び出しを行うと、取り消しスタックが破損することです(フォローアップ操作の取り消しコマンドが最初の操作の前に配置されます)。

私の回避策は、editCommandEndedスロットを使用して機能追加の処理を遅らせることです。これは関連するコードです:

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

これが他の誰かの役に立つことを願っています。


3

うーん、

あなたの答えは本当に素晴らしく、ここで私たちの問題を解決しました。しかし、なぜこれが起こったのかを完全に理解するために、私はそれを解決する方法を知り、QGISソースコードと同僚を研究し、問題を詳細に説明する記事を書きました。お気軽にご確認ください!

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


1
今日でもQGIS v3.4で問題に直面しましたが、あなたの投稿はそれを解決する方法を与えてくれました、これを投稿してくれてありがとう!ところで、私はすでに一年前かそこらのように、あなたの答えをupvotedていた:D
ヘルマン・カリージョ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.