プラグイン開発2
QGISの拡張機能であるプラグインの開発の応用を学びます。
metadata.txt
必須となる幾つかのファイルの内容を見ていきましょう。metadata.txt
はプラグインに関する情報が記載されています。テキストエディタで開いてみましょう。
決められた変数に=
で繋いで値を代入していることがわかります。プラグインビルダーで入れた情報が記載されていますが、必要に応じて書き換えることができます。
general
name=plugin test
qgisMinimumVersion=3.0
description=てすとです
version=0.1
author=asahi
email=asahi@mierune.co.jp
__init__.py
プラグイン読み込みの際に最初に読み込まれるファイルです。classFactory()
という関数を記載しておきます。この中で処理の本体となるモジュールを読み込み、必要なインスタンスを返しています。 QgisInterface
のインスタンスであるiface
が渡されていることを確認しておきましょう。プラグイン内でもifaceを通してQGISを操作することになります。
def classFactory(iface): # pylint: disable=invalid-name
"""Load PluginTest class from file PluginTest.
:param iface: A QGIS interface instance.
:type iface: QgsInterface
"""
#
from .plugin_test import PluginTest
return PluginTest(iface)
処理本体が記載されたファイル
処理が記載されたクラスが最低限持つ必要があるメソッドは、
initGui(): プラグインが使用可になった場合に実行されるメソッド
unload(): プラグインが使用不可になった場合に実行されるメソッド
の2つになります。
plugin_test.py
の内容を見てみましょう。まずはinitGui()
です。
def initGui(self):
"""Create the menu entries and toolbar icons inside the QGIS GUI."""
icon_path = ':/plugins/plugin_test/icon.png'
self.add_action(
icon_path,
text=self.tr(u'plugin test'),
callback=self.run,
parent=self.iface.mainWindow())
# will be set False in run()
self.first_start = True
メニューやツールバーへのプラグインの追加自体は、self.add_action()
で行われています。add_action()
の中の下記の行を見てみましょう。
action = QAction(icon, text, parent)
action.triggered.connect(callback)
QAction
は、メニューやツールバーに追加されるユーザインタフェース部品になります。action
のtriggerd
がcallback
(引数でself.run
が渡されています)にconnect
されています。
作成されたQAction
がツールバーとメニューに追加されているのがわかります。
if add_to_toolbar:
# Adds plugin icon to Plugins toolbar
self.iface.addToolBarIcon(action)
if add_to_menu:
self.iface.addPluginToMenu(
self.menu,
action)
実際に行われる処理は、run()
に書かれています。
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
self.dlg = PluginTestDialog()
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
pass
ここでは、作成済みのダイアログの表示を行っているだけになります。もし何か単一の処理をメニュー/ツールバーから選択された際に行いたいだけであえば、ダイアログの表示部分を削除して、この中に処理を書けばいいことになります。self.iface
からQGISにアクセスもできます。
unload()
も見てみましょう。initGui()
、add_action()
で作成したQAction
をツールバー、メニューから削除していることがわかります。
def unload(self):
"""Removes the plugin menu item and icon from QGIS GUI."""
for action in self.actions:
self.iface.removePluginMenu(
self.tr(u'&plugin test'),
action)
self.iface.removeToolBarIcon(action)
ダイアログの変更
プラグインビルダーを使用すると、空のダイアログは作成してくれます。このダイアログを変更する方法を見てみましょう。 ダイアログの作成/変更には、Qt Designerを利用します。QGISをインストールした際に一緒に入っているので、Windowsのスタートメニューで検索して立ち上げます。
Qt Designerを立ち上げると新しいフォームの作成ウィンドウが表示されます。
「開く」ボタンをクリックして、Plugin Testディレクトリからplugin_test_dialog_base.ui
を開きましょう。
フォームにテキストボックスを配置します。画面左のウィジェットボックスから、”Text Edit”検索します。Text Edit
をドラッグしながら、ダイアログの上に配置します。
配置したText Edit
にプログラムからアクセスする場合には、ウィンドウ右側のプロパティに表示されるobjectName
で識別します。判りやすいものに変えておいた方が良いですが、今回は作成時に入れられる名前のままで進みます。
次にDialog
の領域自体の大きさも変更して、適当な大きさにしておきましょう。オブジェクトを選択した状態でドラッグすると、大きさを調節できます。
レイアウトを整えたら、次にボタンのsignal
が、どのslot
にconnect
されているか確認しておきましょう。ウィンドウ右下のシグナル/スロットエディタ
から確認することができます。
button_box
からのaccepted()
(OKボタンのsignal
)が、dialog
のaccept()
に、rejected()
がdialogのreject()
に、それぞれconnect
されていることがわかります。
button_box
からのsignal
を別なslot
にconnect
する、もしくはdialog
のslot
を上書きしてあげれば処理を変更することができます。
作成の終了したdialog
は、「保存」で上書きしておきましょう。
処理の追記
dialog
のaccept()
を書き換えれば、「OK」ボタンが押された際に処理を追加することができることがわかりました。プラグインビルダーで書きだされているplugin_test_dialog.py
を書き換えて処理を加えましょう。
エクスプローラーからplugin_test_dialog.py
をテキストエディターで開きます。(ここではVisual Studio Codeを使用していますが、ご自分の使っているエディターで構いません。)
PluginTestDialog
クラスは、先ほど変更したplugin_test_dialog_base.ui
を継承するコードが記述されています。
ここでPluginTestDialog
クラスにaccept()
を定義して上書きしましょう。以下のコードを追加して記述してください。ここでは少し回りくどいやり方ですが、accept()
の内容を空にしています。
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'plugin_test_dialog_base.ui'))
class PluginTestDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Constructor."""
super(PluginTestDialog, self).__init__(parent)
# Set up the user interface from Designer.
# After setupUI you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)
#ここに追記 2行
def accept(self):
pass
次に、plugin_test.py
の内容を書き換えます。
run()
が具体的な処理の記述部分です。
(前略)
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
self.dlg = PluginTestDialog()
(以下略)
dialog
を作成した際に、dialog
のbutton_boxのaccepted()
に新しい処理をconnect
します。connect
するメソッドには、レイヤ数をdialog
のtextEdit
に書き出す処理を記述してあります。
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
self.dlg = PluginTestDialog()
#ここに追記 1行
self.dlg.button_box.accepted.connect(self.set_text)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
pass
#ここに追記 2行
def set_text(self):
self.dlg.textEdit.setText(str(self.iface.mapCanvas().layerCount()))
これでプラグインは完成です。
プラグインの実行
QGISに戻り、プラグインを実行してみましょう。プラグインを立ち上げると、ダイアログボックスが増えています。QGISのユーザーインターフェースでレイヤを読み込んでからプラグインのウィンドウに戻り、OK
をクリックするとダイアログボックスに読み込んでいるレイヤの数が表示されます。(以下の例では2つのレイヤを読み込んでいます。)
教材の利用に関するアンケート
本プロジェクトでは、教材の改良を目的とした任意アンケートを実施しています。ご協力いただける方は、アンケートにお進みください。ご協力のほどよろしくお願いいたします。※ 本アンケートの成果は、教材の改良のほか、学会での発表等の研究目的でも利用します。