QGIS3でpythonプラグインを作ってみた その1 ベース作成

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

## はじめに
QGIS3.0がリリースされたので早速プラグインを作ってみようと思う。
今回のバージョンアップではPythonが2.7から3.6に、Qtが4から5に変更になったので既存の自作プラグインはほぼ全滅しています。

> QGIS3へのプラグイン移行
> https://github.com/qgis/QGIS/wiki/Plugin-migration-to-QGIS-3
>
> 後方互換の無い変更
> https://qgis.org/api/api_break.html

## 目標
調べたところPlugin BuilderがQGIS3に対応した「[Plugin Builder3](https://plugins.qgis.org/plugins/pluginbuilder3/)」としてリリースされているのでこれを使ってオリジナルウィンドウが表示されるところまで作っていく。

## Plugin Builder 3のインストール
QGISメニューの[プラグイン]-[プラグインの管理とインストール]を開く。
全てのプラグインタブから「Plugin Builder 3」を選択してプラグインのインストールボタンをクリックでインストールされる。

## Plugin Builder 3をつかう
QGISメニューの[プラグイン]-[Plugin Builder]-[Plugin Builder]で開く。
**全部必須項目**なんで適当に入れていきます。

- **Class name** : クラス名になります。プラグイン名と同じ方がいいと思います。アッパーキャメルケースがいいのかな？日本語を使うと落ちます。
- **Plugin name** : プラグイン名になります。クラス名の複合語をスペースでつなげておけば良いかと。日本語も使えましたが挙動が怪しいので止めておきましょう。
- **Description** : プラグインの概要になります。これいつも悩みますがまあ適当に入れておきましょう。日本語も使えます。
- **Module name** : 生成されるpythonモジュールのベースファイル名になります。こちらもプラグイン名と同じ方がいいと思います。スネークケースがいいのでしょうか？
- **Version number** : バージョン番号です。ご自由にどうぞ。
- **Minimum QGIS version**：対応するQGISの最低バージョンです。ここで指定したバージョン以下ではプラグインの読込ができなくなります。
- **Author/Company** : プラグイン作成者になります。日本語も使えます。
- **Email Address** : 作成者のメールアドレスです。最低でもRFC2606警察に怒られないアドレスにしておきましょう。

今回はこんな感じにしてみました。
![pluginbuilder3_2.png](https://qiita-image-store.s3.amazonaws.com/0/240181/0be4b98e-9d23-b717-ba52-f9bfa02b87ac.png)

Nextボタンをクリックするとプラグインの詳細を入力する画面が開きますが今回はそのままNextボタンをクリックします。
![pluginbuilder3_3.png](https://qiita-image-store.s3.amazonaws.com/0/240181/c3b3b6df-f99f-991f-025c-f29068ddecc2.png)

テンプレートとメニューの場所を設定する画面が開きますので、メニューに表示されるプラグイン名を入力して、他は「Tool button with dialog」と「Plugins」のままNextボタンをクリックします。
![pluginbuilder3_4.png](https://qiita-image-store.s3.amazonaws.com/0/240181/1702be00-a7c0-72e2-e43a-ba3817471fe3.png)

国際化やユニットテストなんかを自動的に作る選択できますが今回はシンプルにしたいのでここは全て外してNextボタンをクリックします。
![pluginbuilder3_5.png](https://qiita-image-store.s3.amazonaws.com/0/240181/10dca530-477d-1c1c-79f3-f9a135ad8dc4.png)

バグトラッカーらリポジトリ等々を設定する画面です。今回は下の実験的プラグインフラグにチェックを付けてその他はそのままでNextボタンをクリックします。
![pluginbuilder3_6.png](https://qiita-image-store.s3.amazonaws.com/0/240181/3f867bf8-3c4b-8538-2362-3718ecbecfcc.png)

保存先を指定してGenerateボタンをクリックします。
モジュール名のサブディレクトリが作られますって書いてありますが実際にはスネークケースのモジュール名だとアンダースコアが消された名称になります。
![pluginbuilder3_7.png](https://qiita-image-store.s3.amazonaws.com/0/240181/496e6afe-7c7f-bdcd-423e-83995c35cd5e.png)

こんな感じのファイル群が作成されました。
![pluginbuilder3_8.png](https://qiita-image-store.s3.amazonaws.com/0/240181/673c540f-13f4-c214-822f-7f18f3ece144.png)

## プラグインの配置
QGIS2系は

```markdown

%USERPROFILE%\.qgis2\python\plugins
```
でしたが

```markdown
%USERPROFILE%\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins
```
に変更されています。無駄に深いよ！！
ではこちらに先ほどのtestpluginをコピーしてQGIS3を起動します。

QGISメニューの[プラグイン]-[プラグインの管理とインストール]を開く。
インストール済みタブから「Test Plugin」を選択して左のチェックを入れるとエラーが出ます。

```markdown

classFactory（）メソッドの呼び出し時にエラーが発生したためプラグイン 'testplugin'を読み込めませんでした 

ModuleNotFoundError: No module named 'testplugin.resources' 
Traceback (most recent call last):
  File "C:/PROGRA~1/QGIS3~1.0/apps/qgis/./python\qgis\utils.py", line 336, in startPlugin
    plugins[packageName] = package.classFactory(iface)
  File "C:/Users/<user>/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\testplugin\__init__.py", line 35, in classFactory
    from .test_plugin import TestPlugin
  File "C:/PROGRA~1/QGIS3~1.0/apps/qgis/./python\qgis\utils.py", line 664, in _import
    mod = _builtin_import(name, globals, locals, fromlist, level)
  File "C:/Users/<user>/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\testplugin\test_plugin.py", line 29, in 
    from .resources import *
  File "C:/PROGRA~1/QGIS3~1.0/apps/qgis/./python\qgis\utils.py", line 664, in _import
    mod = _builtin_import(name, globals, locals, fromlist, level)
ModuleNotFoundError: No module named 'testplugin.resources'
```

リソースファイルが無いって怒られました。
resources.qrcをresources.pyに変換する必要があります。
前バージョンと同じですがテンプレートに入っているresources.qrcをresources.pyにしたのを入れておいてくれてもいい気がするんですがまあそこは色々な考えがあるのでしょう。

## リソースファイルの変換

以前はpyrcc4.exeを使って変換していたので調べてみますが見つかりません。

```
"C:\Program Files (x86)\QGIS 2.18\bin\pyrcc4.exe" -o resources.py resources.qrc
```

検索したらC:\Program Files\QGIS 3.0\apps\Python36\Scripts\pyrcc5.bat
ならありました。調べてみるとpyrcc5.batを動かせばいいみたいです。

pyrcc5.batを叩くとpython36.dllが無いよって怒られますので%PATH%に追加します。
もう一度pyrcc5.batを叩くとPyQt5のimportで落ちますのでそちらも追加してみます。

```
set PATH=%PATH%;C:\Program Files\QGIS 3.0\bin;C:\Program Files\QGIS 3.0\apps\Qt5\bin
```

まだエラーがでますのでこちらのサイト[Python for windows (Python3) パッケージのインストール](http://cha.la.coocan.jp/doc/Python3Package.html)を参考に[Visual Studio 2015 の Visual C++ 再頒布可能パッケージ](https://www.microsoft.com/ja-JP/download/details.aspx?id=48145)からx64版のvc_redist.x64.exeをインストールしたところ動作できるようになりました。

コマンドプロンプトから変換実行

```
C:\Program Files\QGIS 3.0\apps\Python36\Scripts\pyrcc5 -o resources.py resources.qrc
```

###追記
久しぶりにQGIS3.10で動かそうと思ったら以下のエラーが出てしまった。

```
File "C:\PROGRA~1\QGIS3~1.10\apps\Python37\lib\site-packages\PyQt5\pyrcc_main.py", line 21, in <module>
    from PyQt5.QtCore import PYQT_VERSION_STR, QDir, QFile
ImportError: DLL load failed: 指定されたモジュールが見つかりません。
```

QGIS周りの環境変数が足りてなさそうなので以下のコマンドに変更

```
SET QGISPATH="C:\Program Files\QGIS 3.10"
call %QGISPATH%\bin\o4w_env.bat
call %QGISPATH%\bin\qt5_env.bat
call %QGISPATH%\bin\py3_env.bat
%QGISPATH%\apps\Python37\Scripts\pyrcc5 -o resources.py resources.qrc
```

治った。

## 起動
QGISメニューの[プラグイン]-[プラグインの管理とインストール]を開く。
インストール済みタブから「Test Plugin」を選択して左のチェックを入れると今度は正常に起動できました。
![testplugin.png](https://qiita-image-store.s3.amazonaws.com/0/240181/c2730754-2c74-0af4-e858-fdf3cf2174c6.png)

## まとめ
Pythonプラグインの格納場所が変わった

```markdown
%USERPROFILE%\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins
```

リソースファイルの変換方法が変わった
動かないときはPATH追加してC++のライブラリをインストール
（2020/11/01更新 QGISバージョンやPythonバージョンなどのフォルダ名は状況に合わせて変更してください）

```
SET QGISPATH="C:\Program Files\QGIS 3.10"
call %QGISPATH%\bin\o4w_env.bat
call %QGISPATH%\bin\qt5_env.bat
call %QGISPATH%\bin\py3_env.bat
%QGISPATH%\apps\Python37\Scripts\pyrcc5 -o resources.py resources.qrc
```

細かく書きすぎて長くなりましたが、とりあえずウィンドウが表示できましたのでこれを改造してプラグインを作っていきます。
Python3もQt5も未経験なので手探り状態ですが、プラグインを作りながらQGIS2系から3系への移植ポイントなどをまとめたいと考えています。

## 関連記事
[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>の下に提供されています。