QGIS3でpythonプラグインを作ってみた その3 QComboBoxとレイヤ取得について

# QGIS3でpythonプラグインを作る その3

## 目標
[前回](https://qiita.com/ozo360/items/1b8ea895be8ec6d1f5f7)作った地物カウントプラグインを、プラグイン上のコンボボックスで選択したレイヤに対して行うようカスタマイズする。

押さえたいところは

- コンボボックスの扱い方
- レイヤ一覧の取得方法

## 下準備
- 2レイヤ以上登録されたQGISプロジェクトを用意
- 前回作ったプラグインを有効にしておく
- QGISのPluginReloaderプラグインを有効にしておく（任意）

## コンボボックスを配置

```python
self.cmb = QtWidgets.QComboBox(self)
self.cmb.move(30, 20)
```
アイテムの追加は変わりないですね。
表示はレイヤ名で値はレイヤIDにしないといけません。

```python
self.cmb.addItem('')
self.cmb.addItem('a', 'a_123')
self.cmb.addItem('b', 'b_234')
```

選択変更イベントはこんな感じ

```python
self.dlg.cmb.activated.connect(self.comboActivated) 
```

受け側は

```python
def comboActivated(self, index):
    if index > 0:
        layer_id = self.dlg.cmb.itemData(index)
```

## レイヤを取得
今回はベクタレイヤだけを対象としたレイヤリストを作ります。
QGIS2では以下のように取得していました。

```python
vector_layers = []
layermap = QgsMapLayerRegistry.instance().mapLayers()
for id, layer in layermap.iteritems():
    if layer.type() == QgsMapLayer.VectorLayer:
        vector_layers.append(layer.name())
```

QGIS3では`legendInterface`や`QgsMapLayerRegistry`は無くなりましたので
代わりに`QgsProject`を使って取得します。
https://qgis.org/api/classQgsProject.html
またPython3ではディクショナリの`.iteritems()`が無くなりましたので`.items()`を使って回します。

```python
vector_layers = []
layermap = QgsProject.instance().mapLayers()
for key, layer in layermap.items():
    if layer.type() == QgsMapLayer.VectorLayer:
        vector_layers.append(layer.name())
```

レイヤIDでレイヤを取得するには上と同様に`QgsMapLayerRegistry`を`QgsProject`に変更するだけで大丈夫ですね。

```python
QgsMapLayerRegistry.instance().mapLayer(id)
```
　↓

```python
QgsProject.instance().mapLayer(id)
```


## ソースに反映する

画面操作を関数にまとめました。
前回挿入した`self.dlg.btn1.clicked.connect(self.buttonClicked)`は削除して以下のように編集します。

```python:test_plugin.py
...
        # Create the dialog (after translation) and keep reference
        self.dlg = TestPluginDialog(self.iface.mainWindow())
        self.first_flg = True
...
    def run(self):
        """Run method that performs all the real work"""
        self.dlgUpdate()
        # show the dialog
        self.dlg.show()
...
    def dlgUpdate(self):
        if self.first_flg:
            self.dlg.btn1.clicked.connect(self.buttonClicked)
            self.dlg.cmb.activated.connect(self.comboActivated)
            self.first_flg = False
        self.setCmb()
...
    def setCmb(self):
        self.dlg.cmb.clear()
        layermap = QgsProject.instance().mapLayers()
        self.dlg.cmb.addItem('')
        for key, layer in layermap.items():
            if layer.type() == QgsMapLayer.VectorLayer:
                self.dlg.cmb.addItem(layer.name(), key)

    def comboActivated(self, index):
        if index > 0:
            layer_id = self.dlg.cmb.itemData(index)
            layer = QgsProject.instance().mapLayer(layer_id)

            if layer is not None and layer.type() == QgsMapLayer.VectorLayer:
                cnt = layer.featureCount()
                QMessageBox.information(self.dlg,
                                        'count', str(cnt))

```

```python:test_plugin_dialog.py
    def initUI(self):
      self.btn1 = QtWidgets.QPushButton("Button", self)
      self.btn1.move(30, 50)
      self.cmb = QtWidgets.QComboBox(self)
      self.cmb.move(30, 20)
```

## 動作確認
プラグインを再読み込みして起動します。
コンボボックスを選ぶと地物数が表示されました。
![test_plugin_3.png](https://qiita-image-store.s3.amazonaws.com/0/240181/105b0b5c-fb81-7f3d-18a0-ec7d7d7eb3a6.png)


***目的達成です。***

~~でもQGISを再起動してプロジェクト読んですぐにプラグイン起動するとレイヤ一覧がコンボにセットされませんね。:tired_face:
プラグインをリロードするとセットされるようになりますが原因が判りません。
すっきり終わらないの困るなぁ。~~
追記(2018/3/2)：
画面操作関数の呼び出し場所をinitからrunに移動して解決しました。
記事にも修正内容を反映しています。

追記(2018/3/3)：
プラグイン呼び出しをするたびにイベントが追加されてしまっていましたので修正しました。

## まとめ
コンボボックスの使い方は変わらない。
コネクトの仕方は前回のボタンと変わりませんね。
引数指定はしなくてもちゃんと飛ぶみたいです。

```python
# 選択インデックスの場合
self.dlg.cmb.activated.connect(self.comboActivated) 
# 選択文字列の場合
self.dlg.cmb.activated[str].connect(self.comboActivated) 
```

レイヤ一覧の取得は

```python
QgsProject.instance().mapLayers()
```

レイヤIDでレイヤを取得するには

```python
QgsProject.instance().mapLayer(id)
```

ディクショナリを回すときは`.iteritems()`から`.items()`に変更

---

~~この記事のプラグインをGitHubに公開しました。
https://github.com/ozo360/TestPlugin/tree/part3~~

# 次回予告
次回は地物の操作をしてみたいと思います。

## 関連記事
[QGIS3でpythonプラグインを作ってみた その1 ベース作成](https://qiita.com/ozo360/items/399d3257bf4c24bf27e4)
[QGIS3でpythonプラグインを作ってみた その2 QButtonと選択レイヤ取得について](https://qiita.com/ozo360/items/1b8ea895be8ec6d1f5f7)
[QGIS3でpythonプラグインを作ってみた その3  QComboBoxとレイヤ取得について](https://qiita.com/ozo360/items/2c20e304b63b59f07a54)
[QGIS3でpythonプラグインを作ってみた その4  地物の追加編集削除について](https://qiita.com/ozo360/items/68733fea075c1a037367)
[QGIS3でpythonプラグインを作ってみた その5 地図をクリックして地物を選択する](https://qiita.com/ozo360/items/7ab448c57eac5140f2fe)

# 本記事のライセンス

<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">![クリエイティブ・コモンズ・ライセンス](https://i.creativecommons.org/l/by/4.0/88x31.png)</a>
この記事は <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">クリエイティブ・コモンズ 表示 4.0 国際 ライセンス</a>の下に提供されています。