16.1. Struttura Plugin Python
I passi principali per la creazione di un plugin sono:
Idea: Avere un’idea di ciò che si vuole fare con il nuovo plugin QGIS.
Impostazione: Create the files for your plugin. A seconda del tipo di plugin, alcuni sono obbligatori mentre altri sono opzionali
Sviluppo: Write the code nei file appropriati
Documentazione: Write the plugin documentation
Opzionalmente: Tradurre: Translate your plugin in diverse lingue
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. Come iniziare
Prima di iniziare a scrivere un nuovo plugin, dai un’occhiata al Repository ufficiale dei plugin Python. Il codice sorgente dei plugin esistenti può aiutare a imparare di più sulla programmazione. Potresti anche scoprire che esiste già un plugin simile e che potresti essere in grado di estenderlo o almeno di basarti su di esso per sviluppare il tuo.
16.1.1.1. Imposta la struttura dei file del plugin
Per iniziare con un nuovo plugin, dobbiamo impostare i file necessari per il plugin.
Esistono due risorse relative a modelli di plugin che possono aiutarti a iniziare:
A scopo didattico o quando si desidera un approccio minimalista, il minimal plugin template fornisce i file di base (scheletro) necessari per creare un plugin QGIS Python valido.
Per un modello di plugin più completo, il Plugin Builder può creare modelli per diversi tipi di plugin, incluse funzionalità come la localizzazione (traduzione) e il testing.
Una tipica cartella contenente plugin comprende i seguenti file:
metadata.txt
- obbligatorio - Contiene informazioni generali, versione, nome e alcuni altri metadati utilizzati dal sito web e dall’infrastruttura del plugin.__init__.py
- obbligatorio - Il punto di lancio del plugin. Deve avere il metodoclassFactory()
e può avere qualsiasi altro codice di inizializzazione.mainPlugin.py
- codice di base - Il codice di base del plugin. Contiene tutte le informazioni sulle azioni del plugin e il codice di base.form.ui
- per i plugin con GUI personalizzata - L’interfaccia grafica creata da Qt Designer.form.py
- GUI compilata - La traduzione del form.ui descritto sopra in Python.resources.qrc
- opzionale - Un documento .xml creato da Qt Designer. Contiene i percorsi relativi alle risorse utilizzate nei moduli della GUI.resources.py
- risorse compilate, opzionale - La traduzione in Python del file .qrc descritto sopra.
Avvertimento
Se tu vuoi caricare il plugin sul Repository ufficiale dei plugin Python devi controllare che il tuo plugin segua alcune regole aggiuntive, obbligatorie per la Validazione del plugin.
16.1.2. Scrivere codice per i plugin
La sezione seguente mostra il contenuto da aggiungere in ciascuno dei file introdotti in precedenza.
16.1.2.1. metadata.txt
Per prima cosa, il Plugin Manager deve recuperare alcune informazioni di base sul plugin, come il nome, la descrizione ecc. Queste informazioni sono memorizzate in metadata.txt
.
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 |
una tra |
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
(vedremo nella prossima sezione come aggiungere una voce di menu per il tuo plugin), ma possono anche essere inseriti nei menu , , , e .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("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("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.
Anche se le azioni di aiuto e di informazione possono essere aggiunte al menu personalizzato, un posto conveniente per renderle disponibili è il menu principale di QGIS pluginHelpMenu()
.
def initGui(self):
self.help_action = QAction(
QIcon("testplug:icon.png"),
self.tr("Test Plugin..."),
self.iface.mainWindow()
)
# Add the action to the Help menu
self.iface.pluginHelpMenu().addAction(self.help_action)
self.help_action.triggered.connect(self.show_help)
@staticmethod
def show_help():
""" Open the online help. """
QDesktopServices.openUrl(QUrl('https://docs.qgis.org'))
def unload(self):
self.iface.pluginHelpMenu().removeAction(self.help_action)
del self.help_action
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. Documentare plugin
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. Tradurre plugin
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.6. Suggerimenti e trucchi
16.1.6.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.6.2. Automatizzare la pacchettizzazione, il rilascio e la traduzione con qgis-plugin-ci
qgis-plugin-ci fornisce un’interfaccia a linea di comando per eseguire l’impacchettamento e la distribuzione automatizzata dei plugin QGIS sul tuo computer, o utilizzando l’integrazione continua come i flussi di lavoro di GitHub o Gitlab-CI e Transifex per la traduzione.
Permette di rilasciare, tradurre, pubblicare o generare un file XML di repository di plugin tramite CLI o in azioni CI.
16.1.6.3. 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.6.4. Messaggi di Log
I plugin hanno una propria scheda all’interno del Pannello Messaggi di Log.
16.1.6.5. File delle risorse
Alcuni plugin utilizzano file di risorse, ad esempio resources.qrc
che definiscono risorse per la GUI, come le icone:
<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
.