16.1. Struttura Plugin Python
per creare un plugin segui questi passi:
Idea: hai un’idea di ciò che vuoi fare con il tuo nuovo plugin QGIS. Perché lo fai? Che problema vuoi risolvere? C’è già un altro plugin per quel problema?
Crea i file: alcuni sono essenziazli (vedi Plugin file)
Scrivi il codice: scriv il codice nei relativi file
Test: Ricarica il tuo plugin per verificare che tutto è a posto
Pubblica: pubblica il tuo plugin nel repository di QGIS ocrea il tuo repository personale come «magazzino» di «strumenti GIS» personali.
16.1.1. Scrivi un plugin
Dall’introduzione dei plugin Python in QGIS è apparso un numero di plugin. Il gruppo di QGIS mantiene un repository ufficiale di plugin Python. Puoi usarlo per saperne di più sulla programmazione con Pyqgis o vedere se stai duplicando uno sforzo già fatto.
16.1.1.1. Plugin file
Ecco la struttura della cartella del nostro plugin di esempio
PYTHON_PLUGINS_PATH/
MyPlugin/
__init__.py --> *required*
mainPlugin.py --> *core code*
metadata.txt --> *required*
resources.qrc --> *likely useful*
resources.py --> *compiled version, likely useful*
form.ui --> *likely useful*
form.py --> *compiled version, likely useful*
Qual è il significato dei file:
__init__.py
= il punto di partenza del plugin. Deve avere il metodoclassFactory()
e potrebbe avere qualsiasi altro codice di inizializzazione.mainPlugin.py
= il principale codice di lavoro del plugin. Contiene tutte le informazioni sulle azioni del plugin e il codice principale.resources.qrc
= il documento .xml creato da QT Designer. Contiene percorsi relativi alle risorse dei moduli.resources.py
= la traduzione in Python del file .qrc sopra descritto.form.ui
= la GUI creata da QT Designer.form.py
= la traduzione in Python del modulo.UI descritto sopra.metadata.txt
= contiene informazioni generali, versione, nome e alcuni altri metadati utilizzati dal sito web dei plugin e dell’infrastruttura del plugin.
Qui un modo per creare i file di base (scheletro) di un tipico plugin QGIS Python.
C’è un plugin QGIS chiamato Plugin Builder 3 che crea un modello di plugin per QGIS. Questa è l’opzione consigliata, in quanto produce plugin compatibili 3.x.
Avvertimento
Se pensi di caricare il plugin sul repository ufficiale Python Plugin devi verificare che il plugin segua alcune regole aggiuntive, richieste per la convalida Validazione del plugin
16.1.2. Contenuti del plugin
Qui puoi trovare informazioni ed esempi su cosa aggiungere in ciascuno dei file nella struttura del file sopra descritta.
16.1.2.1. Metadati del plugin
Innanzitutto, come creatore del plugin devi recuperare alcune informazioni di base sul plugin come il suo nome, la descrizione ecc. File metadata.txt
è il posto giusto per mettere queste informazioni.
Nota
Tutti i metadati devono essere in codifica UTF-8.
Nome Metadati |
Richiesto |
Note |
---|---|---|
nome |
Vero |
Una breve stringa contenente il nome del plugin |
qgisMinimumVersion |
Vero |
notazione della versione minima di QGIS |
qgisMaximumVersion |
Falso |
notazione della versione massima |
Descrizione |
Vero |
breve testo che descrive il plugin, non in HTML |
su |
Vero |
testo più lungo che descrive il plugin nei dettagli, non è permesso HTML |
versione |
Vero |
corta stringa con la notazione della versione |
autore |
Vero |
nome dell’autore |
Vero |
email dell’autore, mostrato solo sul sito web per l’accesso degli utenti, ma visibile nel gestore plugin solo dopo l’installazione del plugin |
|
cambiamenti |
Falso |
stringa, può essere multilinea, HTML non permesso |
sperimentale |
Falso |
contrassegno, |
deprecato |
Falso |
contrassegno, |
etichette |
Falso |
Elenco separato da virgola, gli spazi sono ammessi all’interno delle singole etichette |
homepage |
Falso |
un URL valido per la pagina iniziale del tuo plugin |
repository |
Vero |
un URL valido per il repository del codice sorgente |
tracker |
Falso |
un URL valido per ticket e bug |
icona |
Falso |
a file name or a relative path (relative to the base folder of the plugin’s compressed package) of a web friendly image (PNG, JPEG) |
categoria |
Falso |
uno di |
plugin_dependencies |
Falso |
Elenco separato da virgole, simile a un PIP, di altri plugin da installare; utilizza i nomi dei plugin provenienti dal campo del nome dei rispettivi metadati. |
server |
Falso |
contrassegno, |
hasProcessingProvider |
Falso |
contrassegno, |
Per impostazione predefinita, i plugin sono inseriti nel menu
(vedrai nella sezione successiva come aggiungere una voce di menu per il plugin) ma possono anche essere inseriti in , , e menus.Una corrispondente voce di metadati: «categoria» esiste per specificare come può essere classificato il plugin. Questa voce dei metadati viene utilizzata per gli utenti e dice loro dove (in quale menu) è possibile trovare il plugin. I valori consentiti per «categoria» sono: vettoriali, raster, database o web. Ad esempio, se il tuo plugin sarà disponibile dal menu raster, aggiungilo a metadata.txt
category=Raster
Nota
Se`qgisMaximumVersion` è vuoto, sarà automaticamente impostata l’ultima versione più .99 quando caricato su Repository ufficiale dei plugin Python.
Un esempio di metadata.txt
; the next section is mandatory
[general]
name=HelloWorld
email=me@example.com
author=Just Me
qgisMinimumVersion=3.0
description=This is an example plugin for greeting the world.
Multiline is allowed:
lines starting with spaces belong to the same
field, in this case to the "description" field.
HTML formatting is not allowed.
about=This paragraph can contain a detailed description
of the plugin. Multiline is allowed, HTML is not.
version=version 1.2
tracker=http://bugs.itopen.it
repository=http://www.itopen.it/repo
; end of mandatory metadata
; start of optional metadata
category=Raster
changelog=The changelog lists the plugin versions
and their changes as in the example below:
1.0 - First stable release
0.9 - All features implemented
0.8 - First testing release
; Tags are in comma separated value format, spaces are allowed within the
; tag name.
; Tags should be in English language. Please also check for existing tags and
; synonyms before creating a new one.
tags=wkt,raster,hello world
; these metadata can be empty, they will eventually become mandatory.
homepage=https://www.itopen.it
icon=icon.png
; experimental flag (applies to the single version)
experimental=True
; deprecated flag (applies to the whole plugin and not only to the uploaded version)
deprecated=False
; if empty, it will be automatically set to major version + .99
qgisMaximumVersion=3.99
; Since QGIS 3.8, a comma separated list of plugins to be installed
; (or upgraded) can be specified.
; The example below will try to install (or upgrade) "MyOtherPlugin" version 1.12
; and any version of "YetAnotherPlugin".
; Both "MyOtherPlugin" and "YetAnotherPlugin" names come from their own metadata's
; name field
plugin_dependencies=MyOtherPlugin==1.12,YetAnotherPlugin
16.1.2.2. __init__.py
Questo file è richiesto dal sistema di importazione di Python. Inoltre, QGIS richiede che questo file contenga una funzione classFactory()
, che viene chiamata quando il plugin viene caricato in QGIS. Riceve un riferimento all’istanza di QgisInterface
e deve restituire un oggetto della classe del tuo plugin dal file mainplugin.py
— nel nostro caso si chiama TestPlugin
(vedi sotto). Questo è come dovrebbe apparire __init__.py
def classFactory(iface):
from .mainPlugin import TestPlugin
return TestPlugin(iface)
# any other initialisation needed
16.1.2.3. mainPlugin.py
Qui è dove avviene e come appare la magia: (e.g. mainPlugin.py
)
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import *
# initialize Qt resources from file resources.py
from . import resources
class TestPlugin:
def __init__(self, iface):
# save reference to the QGIS interface
self.iface = iface
def initGui(self):
# create action that will start plugin configuration
self.action = QAction(QIcon(":/plugins/testplug/icon.png"),
"Test plugin",
self.iface.mainWindow())
self.action.setObjectName("testAction")
self.action.setWhatsThis("Configuration for test plugin")
self.action.setStatusTip("This is status tip")
self.action.triggered.connect(self.run)
# add toolbar button and menu item
self.iface.addToolBarIcon(self.action)
self.iface.addPluginToMenu("&Test plugins", self.action)
# connect to signal renderComplete which is emitted when canvas
# rendering is done
self.iface.mapCanvas().renderComplete.connect(self.renderTest)
def unload(self):
# remove the plugin menu item and icon
self.iface.removePluginMenu("&Test plugins", self.action)
self.iface.removeToolBarIcon(self.action)
# disconnect form signal of the canvas
self.iface.mapCanvas().renderComplete.disconnect(self.renderTest)
def run(self):
# create and show a configuration dialog or something similar
print("TestPlugin: run called!")
def renderTest(self, painter):
# use painter for drawing to map canvas
print("TestPlugin: renderTest called!")
Le sole funzioni plugin che devono esistere nel file sorgente del plugin principale (e.g. mainPlugin.py
) sono:
__init__
che da accesso all’interfaccia QGISinitGui()
chiamata se il plugin è caricatounload()
cchiamata quando il plugin è scaricato
Nell’esempio precedente, viene utilizzato addPluginToMenu()
. Questo aggiungerà l’azione del menu corrispondente al menu . Esistono metodi alternativi per aggiungere l’azione a un menu diverso. Ecco un elenco di quei metodi:
Tutti hanno la stessa sintassi del metodo addPluginToMenu()
.
Si consiglia di aggiungere il tuo menu plugin con uno di questi metodi predefiniti per mantenere la coerenza nel modo in cui sono organizzati i plugin nel menu. Tuttavia, è possibile aggiungere il tuo gruppo di menu personalizzato direttamente alla barra dei menu, come dimostra il prossimo esempio:
def initGui(self):
self.menu = QMenu(self.iface.mainWindow())
self.menu.setObjectName("testMenu")
self.menu.setTitle("MyMenu")
self.action = QAction(QIcon(":/plugins/testplug/icon.png"),
"Test plugin",
self.iface.mainWindow())
self.action.setObjectName("testAction")
self.action.setWhatsThis("Configuration for test plugin")
self.action.setStatusTip("This is status tip")
self.action.triggered.connect(self.run)
self.menu.addAction(self.action)
menuBar = self.iface.mainWindow().menuBar()
menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(),
self.menu)
def unload(self):
self.menu.deleteLater()
Non dimenticare di impostare QAction
e QMenu
objectName
con un nome specifico per il tuo plugin in modo che possa essere personalizzato.
16.1.2.4. File delle risorse
Puoi vedere che in initGui()
abbiamo usato un’icona dal file delle risorse (chiamato nel nostro caso resources.qrc
)
<RCC>
<qresource prefix="/plugins/testplug" >
<file>icon.png</file>
</qresource>
</RCC>
È bene usare un prefisso che non si scontra con altri plugin o parti di QGIS, altrimenti potresti ottenere risorse che non vuoi. Ora hai solo bisogno di generare un file Python che conterrà le risorse. È fatto con il comando pyrcc5:
pyrcc5 -o resources.py resources.qrc
Nota
In ambienti Windows, il tentativo di eseguire pyrcc5 dal prompt dei comandi o PowerShell probabilmente comporterà l’errore «Windows non può accedere al dispositivo, al percorso o al file specificato […].». La soluzione più semplice è probabilmente quella di utilizzare la shell OSGeo4W ma se puoi modificare la variabile ambiente del percorso o specifichi il percorso verso l’eseguibile dovresti essere in grado di trovarela in <Your QGIS Install Directory>\bin\pyrcc5.exe
.
E questo è tutto … niente di complicato :)
Se hai fatto tutto correttamente, dovresti essere in grado di trovare e caricare il tuo plugin nel gestore plugin e vedere un messaggio in console se è selezionata l’icona della barra degli strumenti o la voce di menu appropriata.
Se lavori su un plugin reale è saggio scrivere il plugin in un’altra directory (funzionante) e creare un makefile che genererà file UI + file risorse e installa il plugin nella tuainstallazione QGIS.
16.1.3. Documentazione
Puoi scrivere la documentazione per il plugin come file HTML. Il modulo qgis.utils
fornisce una funzione, showPluginHelp()
che aprirà il browser del file della Guida, allo stesso modo dell’aiuto di QGIS.
La funzione:func:showPluginHelp cerca i file di aiuto nella stessa cartella del modulo di chiamata. Cercherà, a turno, index-ll_cc.html
, index-ll.html
, index-en.html
, index-en_us.html
e index.html
. Qui ll_cc
is the QGIS. Ciò consente a più traduzioni della documentazione da includere nel plugin.
La funzione showPluginHelp()
può anche accettare i parametri packageName, che identifica uno specifico plugin per il quale verrà visualizzata la guida, filename, che può sostituire «index» nei nomi dei file da ricercare, e section, che è il nome di un anchor tag html nel documento su cui verrà posizionato il browser.
16.1.4. Traduzione
Con pochi passaggi puoi impostare l’ambiente per la localizzazione del plugin, in modo che, a seconda delle impostazioni locali del computer, il plugin venga caricato in lingue diverse.
16.1.4.1. Requisiti software
Il modo più semplice per creare e gestire tutti i file di traduzione è installare Qt Linguist. In un ambiente GNU/Linux basato su Debian è possibile installarlo digitando:
sudo apt install qttools5-dev-tools
16.1.4.2. File e cartella
Quando crei il plugin troverai la cartella i18n
all’interno della cartella principale dei plugin.
Tutti i file di traduzione devono trovarsi in questa cartella.
16.1.4.2.1. .pro file
Per prima cosa devi creare un file ``.pro””, cioè un file progetto che può essere gestito da Qt Linguist.
In questo file ``.pro”” devi specificare tutti i file e i moduli che vuoi tradurre. Questo file viene usato per impostare i file di localizzazione e le variabili. Un possibile file di progetto, che corrisponde alla struttura del nostro example plugin:
FORMS = ../form.ui
SOURCES = ../your_plugin.py
TRANSLATIONS = your_plugin_it.ts
Il tuo plugin potrebbe avere una struttura più complessa ed essere distribuito in diversi file. In questo caso, tieni presente che pylupdate5
, il programma che si usa per leggere il file .pro
e aggiornare la stringa traducibile, non espande i caratteri jolly, quindi devi inserire ogni file esplicitamente nel file .pro
. Il file di progetto potrebbe quindi avere un aspetto simile a questo:
FORMS = ../ui/about.ui ../ui/feedback.ui \
../ui/main_dialog.ui
SOURCES = ../your_plugin.py ../computation.py \
../utils.py
Inoltre, il file tuo_plugin.py
è il file che richiama tutti i menu e i sottomenu del tuo plugin nella barra degli strumenti di QGIS e tu vuoi tradurli tutti.
Infine, con la variabile TRANSLATIONS puoi specificare le lingue di traduzione volute.
Avvertimento
Assicurati di denominare il file ts
come tuo_plugin_
+ language
+ .ts
altrimenti il caricamento della lingua fallirà! Utilizza la scorciatoia di 2 lettere per la lingua (it per l’italiano, de per il tedesco, ecc…)
16.1.4.2.2. .ts file
Una volta che hai creato il file .pro
, sei pronto a generare il(i) file .ts
per la lingua(e) del plugin.
Apri un terminale, vai nella cartella tuo_plugin/i18n
e digita:
pylupdate5 your_plugin.pro
dovresti vedere il(i) file tuo_plugin_language.ts
.
Apri il file ``.ts”” con Qt Linguist e inizia a tradurre.
16.1.4.2.3. .qm file
Quando hai finito di tradurre il plugin (se alcune stringhe non sono state completate, verrà usata la lingua di partenza per quelle stringhe), devi creare il file .qm
(il file .ts
compilato che verrà usato da QGIS).
Devi solo aprire un terminale con un cd nella cartella tuo_plugin/i18n
e digitare:
lrelease your_plugin.ts
ora, nella cartella i18n
vedrai il(i) file tuo_plugin.qm
.
16.1.4.3. Tradurre con Makefile
In alternativa, puoi usare il makefile per estrarre i messaggi dal codice python e dalle finestre di dialogo Qt, se hai creato il plugin con Plugin Builder. All’inizio del Makefile c’è una variabile LOCALES:
LOCALES = en
Aggiungi l’abbreviazione della lingua a questa variabile, ad esempio per la lingua ungherese:
LOCALES = en hu
Ora puoi generare o aggiornare il file hu.ts
(e anche en.ts
) dai sorgenti da:
make transup
In questo modo, hai il file .ts
aggiornato per tutte le lingue impostate nella variabile LOCALES. Utilizza Qt Linguist per tradurre i messaggi del programma. Al termine della traduzione, i file .qm
possono essere creati da transcompile:
make transcompile
Devi installare i file ``.ts”” con il tuo plugin.
16.1.4.4. Caricare il plugin
Per vedere la traduzione del plugin, apri QGIS, cambia la lingua (:menuselection: Impostazioni –> Opzioni –> Generale) e riavvia QGIS.
Dovresti vedere il tuo plugin nella lingua corretta.
Avvertimento
Sei modifichi qualcosa nel plugin (nuove UI, nuovi menu, ecc.) devi generare nuovamente la versione aggiornata di entrambi i file .ts
e .qm
, quindi eseguire nuovamente il comando di cui sopra.
16.1.5. Suggerimenti e trucchi
16.1.5.1. Plugin Reloader
Durante lo sviluppo del tuo plugin sarà spesso necessario ricaricarlo in QGIS per testarlo. Questo è molto semplice utilizzando il plugin Plugin Reloader. È possibile trovarlo con il comando Plugin Manager.
16.1.5.2. Accessere ai plugin
Puoi accedere a tutte le classi dei plugin installati dall’interno di QGIS usando python, il che può essere utile a fini di debug.
my_plugin = qgis.utils.plugins['My Plugin']
16.1.5.3. Messaggi di Log
I plugin hanno una propria scheda all’interno del Pannello Messaggi di Log.