PyQGIS LayerTreeViewのサンプル


どんな動きをするの?

f:id:Chiakikun:20200611220049p:plain

レイヤウィンドウでレイヤを選択する度に...

 

f:id:Chiakikun:20200611220102p:plain

選択されていたレイヤ名と、現在選択されているレイヤ名がPythonコンソールに表示されます。


コード

import qgis
from qgis.core import *
from qgis.gui  import *
from PyQt5.Qt import QObject, pyqtSignal

class LayerTreeViewSample(QObject): # signal-slot使いたいので
    cleared = pyqtSignal()

    def changeLayer(self, layer):

        if (layer == None): # レイヤウィンドウに何も無い状態
            self.currentlayer = None
            self.cleared.emit()
            return

        if self.currentlayer != None:
            print(self.currentlayer.name() + 'が非アクティブになりました。')

        print(layer.name()+'がアクティブになりました。')
        self.currentlayer = layer


    def __init__(self, iface):
        super(LayerTreeViewSample, self).__init__()

        self.iface = iface

        self.currentlayer = self.iface.layerTreeView().currentLayer()
        self.iface.layerTreeView().currentLayerChanged.connect(self.changeLayer)


    def __del__(self):
        self.iface.layerTreeView().currentLayerChanged.disconnect(self.changeLayer)

ソースはこちら


使い方

例として、ここからダウンロードできるサンプルプラグインに追加します。

nodialog_skelton.pyと同じフォルダにソースを置いて、インポート部分に次のコードを追記します。

from .layertreeviewsample import LayerTreeViewSample

nodialog_skelton.pyのstartを次のコードに書き換えます。

    def start(self):
        self.lt = LayerTreeViewSample(self.iface)
        self.lt.cleared.connect(self.clear)

nodialog_skelton.pyのfinishを次のコードに書き換えます。

    def finish(self):
        self.lt = None

次のメソッドを追加してください。

    def clear(self):
        self.lt = None
        self.action.setChecked(False)

def clear(self): self.lt = None self.action.setChecked(False)

このようになればOKです。

~略~

from .layertreeviewsample import LayerTreeViewSample


class NodialogSkelton(qgis.gui.QgsMapTool):

    def clear(self):
        self.lt = None
        self.action.setChecked(False)


    def start(self):
        self.lt = LayerTreeViewSample(self.iface)
        self.lt.cleared.connect(self.clear)
        
        
    def finish(self):
        self.lt = None
~略~

ありがとうございました。

PyQGIS 一時レイヤ作成サンプル


どんな動きをするの?

プラグイン実行時に一時レイヤを作成し、終了時に一時レイヤを削除します。以前紹介したラバーバンドのサンプルを使って、オブジェクトを一時レイヤに追加できるようにしました。


コード

import qgis
from qgis.core import *
from qgis.gui  import *

class TemporaryLayer:
    def __init__(self, iface, canvas, layername, type, fields): # type = Point or LineString, Polygon

        self.canvas = canvas
        self.iface = iface

        fieldsstr = ''
        for f in fields:
            fieldsstr += '&field=' + f

        epsg = iface.mapCanvas().mapSettings().destinationCrs().authid()
        self.layer = QgsVectorLayer(type + '?&crs='+epsg+fieldsstr, layername, 'memory')

        QgsProject.instance().addMapLayer(self.layer)

    def addFeature(self, geometry, attrs):

            qf = QgsFields()
            for field in self.layer.fields():
                qf.append(QgsField(str(field.name()), typeName=field.typeName()))
            record = QgsFeature(qf) 

            # 地物をセットする
            record.setGeometry(geometry) 

            # 属性をセットする
            record.setAttributes(attrs)

            # 作成したレコードをレイヤに追加
            self.layer.dataProvider().addFeatures([record])
            self.layer.updateExtents() # これが無いと『レイヤの領域にズーム』した時に、レイヤの最初のオブジェクト部分しかズームされない

            self.canvas.refreshAllLayers()


    def __del__(self):
        self.canvas.refreshAllLayers()
        QgsProject.instance().removeMapLayer(self.layer.id())

ソースはこちら


使い方

例として、ここからダウンロードできるサンプルプラグインに追加します。

地物を追加したいので、こちらで紹介したrubberbandSample.pyも使います。

nodialog_skelton.pyと同じフォルダにソースを置いて、インポート部分に次のコードを追記します。

from .rubberbandSample import RubberBandSample
from .temporarylayer import TemporaryLayer

nodialog_skelton.pyのstartを次のコードに書き換えます。

    def start(self):
        maptool = RubberBandSample(self.iface, self.canvas, QgsWkbTypes.PolygonGeometry)  # ポリゴンの場合
        maptool.getObject.connect(self.setFeature)

        fields = [
            'id:integer',
            'name:string'
        ]
        self.tmp = TemporaryLayer(self.iface, self.canvas, '一時レイヤ', 'Polygon', fields)

        self.canvas.setMapTool(maptool)
        self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合

nodialog_skelton.pyのfinishを次のコードに書き換えます。

    def finish(self):
        self.tmp = None
        self.canvas.mapToolSet.disconnect(self.unsetTool)

次のメソッドを追加します。

    def setFeature(self, geom):
        self.tmp.addFeature(geom, [])

このようになればOKです。

~略~
from .rubberbandSample import RubberBandSample
from .temporarylayer import TemporaryLayer

class NodialogSkelton(qgis.gui.QgsMapTool):

    def setFeature(self, geom):
        self.tmp.addFeature(geom, [])


    def start(self):
        maptool = RubberBandSample(self.iface, self.canvas, QgsWkbTypes.PolygonGeometry)  # ポリゴンの場合
        maptool.getObject.connect(self.setFeature)

        fields = [
            'id:integer',
            'name:string'
        ]
        self.tmp = TemporaryLayer(self.iface, self.canvas, '一時レイヤ', 'Polygon', fields)

        self.canvas.setMapTool(maptool)
        self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合


    def finish(self):
        self.tmp = None
        self.canvas.mapToolSet.disconnect(self.unsetTool)
~略~

緑の箇所はラバーバンドサンプルの時の設定箇所で、赤い箇所は今回紹介させていただいた一時レイヤ作成のための設定箇所です。


最後までご覧頂き、ありがとうございました

PyQGIS 属性編集ダイアログのサンプル


どんな動きをするの?

f:id:Chiakikun:20200531141501p:plain

ベクタレイヤの地物を一つ選択した状態でプラグインを実行すると、上の画像のような属性編集ダイアログが表示されます。


コード

import qgis
from qgis.gui  import *

class AttributeEditorSample:

    def editAttribute(self, layer):
        features = layer.selectedFeatures()
        if len(features) == 0:
            return

        self.layer = layer

        self.layer.startEditing() # レイヤを編集状態にする

        # 選択しているフューチャーの属性フォーム表示
        self.attdlg = self.iface.getFeatureForm(self.layer, features[0])
        self.attdlg.setMode(QgsAttributeEditorContext.SingleEditMode)
        self.attdlg.finished.connect(self.commitEdit)
        self.attdlg.show()


    def commitEdit(self, result):
        if result == 1:
            self.layer.commitChanges()
        else:
            self.layer.rollBack()
        self.attdlg.finished.disconnect(self.commitEdit)


    def __init__(self, iface):
        self.iface = iface

ソースはこちら


試しに使ってみる

例として、ここからダウンロードできるサンプルプラグインに追加します。

nodialog_skelton.pyと同じフォルダにソースを置いて、インポート部分に次のコードを追記します。

from .attributeeditorsample import AttributeEditorSample

nodialog_skelton.pyの__init__にcheckableを設定しているところがあるので、Trueが設定されている場合はFalseに変更します。

    self.checkable = False

startを次のコードに変更します。

    def start(self):
        self.ae = AttributeEditorSample(self.iface)
        self.ae.editAttribute(self.iface.activeLayer())

次のようになればOKです。

~略~

from .attributeeditorsample import AttributeEditorSample

~略~
class NodialogSkelton(qgis.gui.QgsMapTool):

    def start(self):
        self.ae = AttributeEditorSample(self.iface)
        self.ae.editAttribute(self.iface.activeLayer())
~略~

    def __init__(self, iface):
        self.plugin_name = 'ダイアログ無し雛形' # プラグイン名
        self.menu_pos    = '雛形'               # プラグインの登録場所(このサンプルの場合、メニューの「プラグイン/雛形/ダイアログ無し雛形」)
        self.toolbar     = True                 # Trueならツールバーにアイコンを表示する
        self.checkable   = False                 # Trueならプラグイン実行中はアイコンが凹んだままになる
~略~

最後までご覧頂き、ありがとうございました