Zásuvné moduly, tzv. pluginy představují doplňkové nástroje. Jejich úlohou je rozšiřovat funkčnost a širokou škálu použití prostředí QGIS. Úvod do této problematiky je součástí školení QGIS pro začátečníky.

V mnohých případech však může nastat situace, kdy žádný z existujících zásuvných modulů nesplňuje funkcionalitu jakou bychom právě potřebovali. Úroveň rozšiřovaní funkcionality QGIS je různorodá. Za pomoci jazyka Python může jít o přidání jednoduchého tlačítka až po tvorbu sofistikovaných nástrojů. Kromě jazyka Python lze psát zásuvné moduly i v jazyku, ve kterém je napsán samotný QGIS, a to C++. To ale není úplně běžné.

V následující části načrtneme návod, jak si vlastní plugin vytvořit. Použijeme výše uvedený programovací jazyk Python. Postup následně odzkoušíme na jednoduchém reálném příkladu. Vytvoříme zásuvný modul s názvem Save Views, který exportuje grafický výstup ve formě obrázků ve formátu PNG pro každý prvek ve vybrané vektorové vrstvě do zvoleného výstupního adresáře.

Užitečné odkazy

Důležité

QGIS verze 2 a 3 se významně liší, a to nejen z uživatelského pohledu, ale i tvorby pluginů. QGIS API verze 3 není s předcházející verzí zpětně kompatibilní. Obsahuje řadu změn, viz Backwards Incompatible Changes. Tento návod je psán pro verzi QGIS 3.

Potřebné nástroje

I. Qt Designer

Pro tvorbu nového pluginu budeme potřebovat Qt Designer, což je aplikace vývojového frameworku Qt. Tento nástroj využijeme pro tvorbu uživatelského rozhraní nového modulu.

Poznámka

Způsob instalace Qt Designer se liší podle platformy. Na Windows je Qt Designer součástí instalace samotného QGISu. Doporučený postup je použít instalátor OSGeo4W, vybrat volbu Express Desktop a nainstalovat balík QGIS. Qt Designer spustíme přes volbu Qt Designer with QGIS custom widgets. V případě Ubuntu/Debian je Qt Designer součástí balíčku qttools5-dev-tools.

II. Python rozhraní pro Qt

Vzhledem k tomu, že budeme vyvíjet plugin v programovacím jazyku Python, musíme nainstalovat Python rozhraní (Python bindings) pro Qt (verze 5). Pro tvorbu zásuvných modulů je potřeba také nástroj pyrcc5.

Poznámka

Na Windows obsahuje instalátor OSGeo4W vše potřebné. Po instalaci je nástroj pyrcc5 dostupný v rámci OSGeo4W Shell. Na Mac OS je potřeba nainstalovat správce balíčků Homebrew a doinstalovat balíček PyQt. V případě Linuxu (Ubuntu/Debian) jde o balíček pyqt5-dev-tools. V Ubuntu jej např. nainstalujeme příkazem sudo apt-get install pyqt5-dev-tools.

III. Textový editor

Vhodný textový editor anebo integrované vývojové prostředí (IDE) jsou pro psaní zdrojového kódu důležité. Mezi oblíbené editory patří například Sublime Text, Vim, GNU Emacs, Notepad++, TextWrangler, IDLE, Atom, Aquamacs, GNU Nano, Kate, gedit, prostředí Spyder či PyCharm a podobně.

Poznámka

V našem případě si vystačíme s vestavěným Python editorem v QGISu. Pro dlouhodnou práci tento editor ale vhodný není.

IV. Zásuvný modul Plugin Builder

Tento velmi užitečný zásuvný modul QGISu nám pomůže vytvořit všechny potřebné soubory a standardní podobu kódu pro budoucí plugin. Nainstalujeme jej klasickým způsobem pomocí správce zásuvných modulů v QGISu, viz. školení QGIS pro začátečníky.

../_images/plugin-builder.png

Obr. 1 Instalace zásuvného modulu Plugin Builder.

V. Zásuvný modul Plugin Reloader

Díky tomuto pluginu nemusíme při každé změně našeho kódu restartovat QGIS. Změny se projeví ihned po jeho spuštění. Nainstalujeme jej klasickým způsobem pomocí správce zásuvných modulů v QGISu (pro jeho instalaci je potřeba povolit experimentální moduly v nastavení správce).

../_images/plugin-reloader.png

Obr. 2 Instalace zásuvného modulu Plugin Reloader.

Pět základních kroků pro vytvoření pluginu Save Views

1. Vytvoření šablony nového pluginu pomocí zásuvného modulu Plugin Builder

2. Překlad qrc souboru

3. Načtení nového pluginu ve správci zásuvných modulů

4. Vytvoření uživatelského rozhraní pomocí Qt Designer

5. Implementace funkcionality pluginu v rámci Python kódu

1. Vytvoření šablony nového pluginu

Po spuštění zásuvného modulu pro tvorbu pluginů plugin-builder se objeví dialogové okno, kde zadáme základní údaje o našem novém nástroji, viz. Obr. 3.

../_images/plugin-builder-0.png

Obr. 3 Dialogové okno zásuvného modulu na tvorbu pluginů. Zde vyplníme základní udáje.

Poznámka

Class name je název Python třídy a Module name název adresáře. U těchto položek nepoužívejte diakritiku, mezery a pod.

../_images/plugin-builder-1.png

Obr. 4 Na další stránce průvodce vyplníme podrobné informace o našem nástroji (About).

V třetí části vybereme šablonu uživatelského prostředí. K dispozici jsou tři:

  • Tool button with dialog (samostatné okno)
  • Tool button with dockwidget (přichytnutelné okno)
  • Processing provider (poskytovatel pro nástoje zpracování, viz školení QGIS pro pokročilé)
../_images/plugin-builder-2.png

Obr. 5 V našem případě zvolíme Tool button with dockwidget.

Zadáme text, který se bude zobrazovat v menu. Nakonec vybereme, pod kterou položkou v menu náš nový plugin uživatel najde.

../_images/plugin-builder-3.png

Obr. 6 Na dalších stránce průvodce je možné ovlivnit vytvoření dalších podpůrných souborů (lokalizace, nápověda, …).

../_images/plugin-builder-4.png

Obr. 7 Dále je možné vyplnit povinné a volitelné informace, například domovskou stránku, repositář modulu se zdrojovými kódy, označit nástroj jako experimentální a podobně. Tyto udaje lze doplnit ale později. Ponecháme prozatím výchozí hodnoty.

Následně se objeví okno, kde je potřebné zadat cestu, ve kterém se adresář s vytvořeným pluginem vytvoří. Zvolíme vhodné umístění na vašem disku, v našem případě /opt/qgis_plugins.

../_images/plugin-builder-5.png

Obr. 8 Cílový adresář, kde se vytvoří šablona s pluginem.

Po tomto kroku se objeví potvrzující dialog, tzv. Plugin Builder Results obsahující souhrnné informace.

../_images/plugin-builder-6.png

Obr. 9 Souhrné informace o vytvořeném pluginu.

Na tomto místě najdete jednu podstatnou informaci, a to cestu k adresáři, kde vaše instalace QGISu hledá při načítání zásuvné moduly. Tato cesta je závislá na platfomě. Pod Linuxem je to typicky $HOME/.local/share/QGIS/QGIS3/profiles/default/python/plugins. Pod Windows %APPDATA%\Roaming\QGIS\QGIS3\profiles\default\python\plugins.

2. Překlad qrc souboru

Důležité

Tento krok provede Plugin Builder automaticky, pokud je v systémové cestě dostupný nástroj pyrcc5.

Otevřte adresář s vytvořeným pluginem, v našem případě /opt/qgis_plugins/save_views. Pokud se soubor resources.py nevytvořil, je potřeba to napravit. Spustíme z příkazové konzole příkaz make. Ten vytvoří na základě Resource Collection File (*.qrc) jeho Python přepis. Jde vlastně o spuštění výše uvedeného pyrcc5.

3. Načtení nového pluginu ve správci zásuvných modulů

K tomu, aby nový plugin QGIS po startu našel, existuje více možností. Nejjednoduší variantou je adresář s pluginem překopírovat do výchozí cesty zásuvných modulů, viz Krok 1. Lepší variantou je definovat v nastavení QGISu (Nastavení ‣ Možnosti ‣ Systém) proměnnou prostředí QGIS_PLUGINPATH ukazující na nadřazený adresář vašeho pluginu, tj. /opt/qgis_plugins. Po restartu bude QGIS zobrazovat všechny pluginy, které do tohoto adresáře v budnoucnu umístíte.

../_images/qgis-pluginpath.svg

Obr. 10 Nastavení proměnné prostředí QGIS_PLUGINPATH.

Po opětovném startu QGISu by měl být v sekci Zásuvné moduly ‣ Spravovat a instalovat zásuvné moduly viditelný i plugin Save Views. Zaškrtnutím box_yes se objeví jeho ikona npicon a nová položka v hlavním menu, tak jako jsme zadali, tj. v sekci Zásuvné moduly ‣ Save Views.

../_images/save-views-enable.png

Obr. 11 Aktivace zásuvného modulu Save Views.

Spuštěním npicon otevřeme dialog nástroje, který obsahuje popisek (Obr. 12).

../_images/plugin-ui-template.png

Obr. 12 Okno modulu Save Views po prvním spuštění.

Tip

V této fázi je dobré se zamyslet nad funkcionalitou pluginu, jaký bude typ vstupních dat a podobně. Na základě našich požadavků je vhodné si vytvořit testovací sadu.

Vytvoříme si jednoduchý projekt v QGISu, který bude obsahovat několik vektorových vrstev. Na Obr. 13 jsou zobrazeny například požární stanice, železnice, kraje, velkoplošné území a státní hranice České republiky.

../_images/qgis-project.png

Obr. 13 Příklad projektu s vektorovými vrstvami v QGIS.

4. Vytvoření uživatelského rozhraní pomocí Qt Designer

Vzhled a elementy dialogového okna pluginu budeme upravovat v programu Qt Designer. V hlavní liště zvolíme File ‣ Open File or Project a otevřeme soubor s příponou *.ui. V našem případě save_views_dockwidget_base.ui, který najdeme v adresáři vytvořeného pluginu. Na Obr. 14 je znázorněné prozatím prázdné okno (SaveViewsDockWidgetBase) s objekty (tzv. widgety) dockWidgetContets a label. Pomocí metody drag-and-drop je možné z levého panelu přidávat další objekty a jejich názvy a vlastnosti měnit v pravé části okna aplikace Qt Designer.

../_images/qt-designer.png

Obr. 14 Dialogové okno vytvářeného pluginu v prostředí aplikace Qt Designer.

Nejrpve v pravém panelu změníme předvolený text objektu label na Select a layer (Obr. 15).

../_images/qt-label.svg

Obr. 15 Editace objektů dialogového okna.

Dále v levé části okna najdeme objekt typu Combo Box a tažením myši jej umistíme do vhodného místa okna zásuvného modulu.

../_images/qt-combobox.png

Obr. 16 Přidání nového widgetu typu Combo Box.

Tip

Pro reálný vývoj je vhodné výchozí názvy objektů (v našem případě label a comboBox) nastavit na hodnoty odpovídajícím reálnému využití, např.místo combobox layerSelect a pod.

Po uložení File ‣ Save přejdeme do prostředí QGIS, kde použijeme plugin Plugin Reloader |plugin-reloader|. V Choose a plugin to be reloaded nastavíme SaveViews (Obr. 17) a plugin spustíme. Tím se aktualizuje podoba našeho pluginu.

../_images/plugin-reloaded.png

Obr. 17 Konfigurace zásuvného modulu Plugin Reloader.

Po kliknutí na ikonu npicon se otevře okno odpovídající návrhu na Obr. 15.

../_images/plugin-ui-combo.png

Obr. 18 Okno modulu Save Views po úpravě uživatelského rozhraní.

5. Implementace funkcionality nástroje a další úpravy

Řekněme, že chceme, aby se po spuštění pluginu Combo Box automaticky naplnil vektorovými vrstvami aktuálního projektu. Hlavním souborem, který se stará o logiku jednotlivých objektů, je v našem případě save_views.py. Otevřeme jej v textovém editoru a najdeme metodu run(). Tato metoda se spouští při každém startu pluginu. Na její konec umístíme následující kód (Obr. 19).

# populate the Combo Box with the vector layers loaded in QGIS
from qgis.core import QgsProject, QgsMapLayer
self.dockwidget.comboBox.clear()
for layer in QgsProject.instance().mapLayers().values():
    if layer.type() != QgsMapLayer.VectorLayer:
        continue
    self.dockwidget.comboBox.addItem(layer.name())
../_images/run-method.svg

Obr. 19 Úprava zdrojového kódu s cílem naplnit Combo Box vektorovými vrstvami.

Po znovu načtení pluginu |plugin-reloader| a jeho otevření npicon je vidět, že se změny úspěšně projevily (Obr. 20).

../_images/vector-select.png

Obr. 20 Vzhled dialogového okna po změnách ve zdrojovém kódu.

Poznámka

V případě, že skončí spustění či znovunačtení chybou, tak hledejte relevatní informace ve Zprávách výpisů, konkrétně v záložce Python chyba.

../_images/python-errors.png

Tip

Namísto obecného objektu Combo Box by bylo možné použít specifický widget QGISu, a to QgsMapLayerComboBox. Využití tohoto specifického widgetu by nám ušetřilo pár řádek kódu.

Todo

doplnit nazev tridy

Úkol

Seznam vrstev se načítá pouze při spuštění pluginu. Upravte zdrojový kód tak, aby umožňoval znovunačtení seznamu vrstev i během běhu pluginu.

Obdobně vložíme do okna další elementy a přiřadíme jim příslušnou funkcionalitu. Kromě popisu Select output directory půjde o objekty Line Edit, Tool Button, Push Button. U widgetu pushButton ve vlastnostech změníme text na Save All. Nastavíme přiměřené rozměry pro každý element a upravený soubor uložíme. Důležité jsou názvy jednotlivých objektů, viz. Obr. 21, budeme je ještě potřebovat.

../_images/plugin-ui-final.svg

Obr. 21 Finální návrh uživatelského rozhraní pluginu Save Views.

Poznámka

Pokud je uživatelské rozhraní definováno více objekty (widgety) je vhodné je rozumně pojmenovat. V případě našeho jednoduchého modulu si vystačíme s předvolenými názvy.

V dalším kroku potřebujeme přidat kód, který zabezpečí, aby se po kliknutí na tlačítko ... otevřel dialog, ve kterém zvolíme adresář pro uložení výsledných obrazových souborů pro každý prvek ve vybrané vektorové vrstvě. O tuto funkcionalitu se postará nová metoda select_output_directory(), kterou přidáme na konec souboru save_views.py, Obr. 22.

# open directory browser and populate the line edit widget
def select_output_dir(self):
    from PyQt5.QtWidgets import QFileDialog
    self.dirname = QFileDialog.getExistingDirectory(
        self.dockwidget, "Select directory ", os.path.expanduser("~")
    )
    self.dockwidget.lineEdit.setText(self.dirname)

Tip

os.path.expanduser("~") nastaví cestu při otevření dialogu na domovský adresář.

Poznámka

Kód importující použité třídy jako např. from PyQt5.Widgets import QFileDialog je vhodnější umístit na začátek souboru. Zde uvádíme především pro přehlednost úprav.

../_images/np_select_output_dir.png

Obr. 22 Metoda, která otevře dialog pro výběr výstupního adresáře.

Úkol

Upravte zdrojový kód tak, aby si dialog pamatoval poslední použitý adresář.

Následně propojíme metodu select_output_dir() s tlačítkem toolButton (tlačítko ...). To provedeme přidáním níže uvedených řádků do metody __run__(), nejlépe na konec těla podmínky if self.dockwidget == None, viz Obr. 22.

# connect the select_output_file() method to the clicked signal of the tool button widget
self.dockwidget.toolButton.clicked.connect(self.select_output_dir)

Na konec metody __run__() ještě přidáme kód zajišťující obnovení prázdného obsahu objektu lineEdit.

# clear the previously loaded text (if any) in the line edit widget
self.dockwidget.lineEdit.clear()
../_images/select-output-dir.svg

Obr. 23 Úpravy v kódu zajišťující propojení metody select_output_dir() a tlačítka ....

Soubor uložíme, plugin znovu načteme a vyzkoušíme (Obr. 24).

../_images/plugin-test-1.png

Obr. 24 Načtení adresáře pro grafické výstupy pomocí nového pluginu.

Posledním krokem je změnit to, aby se po kliknutí na tlačítko Save all opravdu provedlo, co chceme. Vytvoříme novou metodu save_views(), kterou umístíme na konec souboru save_views.py, viz Obr. 25.

def save_views(self):
     from PyQt5.QtGui import QColor, QPixmap
     from qgis.core import QgsProject
     from qgis.utils import iface

     # save graphical output for every row in attribute table
     layer_name = self.dockwidget.comboBox.currentText()
     layer = QgsProject.instance().mapLayersByName(layer_name)[0]

     for feature in layer.getFeatures():
         layer.selectByIds([feature.id()])
         self.iface.mapCanvas().setSelectionColor(QColor("transparent"));
         box = layer.boundingBoxOfSelected()
         self.iface.mapCanvas().setExtent(box)
         pixmap = QPixmap(self.iface.mapCanvas().mapSettings().outputSize().width(),
                          self.iface.mapCanvas().mapSettings().outputSize().height()
         )
         mapfile = os.path.join(self.dirname, '{0}_{1:03d}.png'.format(layer_name, feature.id()))
         self.iface.mapCanvas().saveAsImage(mapfile, pixmap)
         layer.removeSelection()

     # save also full extend of vector layer
     canvas = self.iface.mapCanvas()
     canvas.setExtent(layer.extent())
     pixmap = QPixmap(self.iface.mapCanvas().mapSettings().outputSize().width(),
                      self.iface.mapCanvas().mapSettings().outputSize().height()
     )
     mapfile = os.path.join(self.dirname, '{}_full.png'.format(layer_name))
     self.iface.mapCanvas().saveAsImage(mapfile, pixmap)

Tuto metodu provážeme s tlačítkem Save all.

# connect the save_views() method to the clicked signal of the push button widget
self.dockwidget.pushButton.clicked.connect(self.save_views)
../_images/save_views.svg

Obr. 25 Doplnění kódu do metody run().

Úkol

Opravte chybu, která nastane po stisknutí tlačítka Save all v případě, že není nastaven adresář pro výstupní soubory.

Úkol

Upravte kód tak, aby mohl zadat uživatel výstupní adresář ručně bez tlačítka ....

Grafické výstupy po aplikovaní na vrstvu krajů jsou zobrazeny na Obr. 26. Jejich názvy v adresáři závisí na názvu konkrétní vektorové vrstvy. Liší se pouze pořadovým číslem.

../_images/save-views-result.png

Obr. 26 Grafické soubory uložené ve zvoleném adresáři pro vektorovou vrstvu krajů České republiky.

Tip

V případě, že chceme změnit ikonu, stačí nový soubor s ikonkou, např. Obr. 27, uložit do adresáře save_views jako soubor icon.png a spustit příkaz make clean && make v příkazové řádce. Nakonec znovunačteme plugin pomocí modulu Plugin Reloader.

../_images/np_new_icon.png

Obr. 27 Příklad nové ikonky

Výsledný soubor save_views.py je ke stažení také zde.

Jiný příklad využití

Na obrázku Obr. 28 je uveden projekt s katastrálními daty. Vyznačené jsou parcely, přes které budou procházet plánované inženýrské sítě.

../_images/np_kn_project.png

Obr. 28 Znázornění parcel přes které májí procházet plánované inženýrské sítě.

Použitím pluginu Save Views můžeme pro každého vlastníka vyhodnotit grafické znázornění jeho parcely, na které bude zapsané věcné břemeno (Obr. 29).

../_images/np_kn_project_views.png

Obr. 29 Pohled na každou parcelu jako výsledek zásuvného modulu Save Views.