16.1. Structurer les plugins Python
The main steps for creating a plugin are:
Idea: Have an idea about what you want to do with your new QGIS plugin.
Setup: Create the files for your plugin. Depending on the plugin type, some are mandatory while others are optional
Develop: Write the code in appropriate files
Document: Write the plugin documentation
Optionally: Translate: Translate your plugin into different languages
Tester: Rechargez votre extension pour vérifier si tout est OK
Publier : Publiez votre plugin dans le dépôt QGIS ou créez votre propre dépôt comme un « arsenal » d“« armes SIG » personnelles.
16.1.1. Getting started
Before starting to write a new plugin, have a look at the Dépôt officiel des extensions QGIS. The source code of existing plugins can help you to learn more about programming. You may also find that a similar plugin already exists and you may be able to extend it or at least build on it to develop your own.
16.1.1.1. Set up plugin file structure
To get started with a new plugin, we need to set up the necessary plugin files.
There are two plugin template resources that can help get you started:
For educational purposes or whenever a minimalist approach is desired, the minimal plugin template provides the basic files (skeleton) necessary to create a valid QGIS Python plugin.
For a more fully feature plugin template, the Plugin Builder can create templates for multiple different plugin types, including features such as localization (translation) and testing.
A typical plugin directory includes the following files:
metadata.txt
- required - Contains general info, version, name and some other metadata used by plugins website and plugin infrastructure.__init__.py
- required - The starting point of the plugin. It has to have theclassFactory()
method and may have any other initialisation code.mainPlugin.py
- core code - The main working code of the plugin. Contains all the information about the actions of the plugin and the main code.form.ui
- for plugins with custom GUI - The GUI created by Qt Designer.form.py
- compiled GUI - The translation of the form.ui described above to Python.resources.qrc
- optional - An .xml document created by Qt Designer. Contains relative paths to resources used in the GUI forms.resources.py
- compiled resources, optional - The translation of the .qrc file described above to Python.
Avertissement
If you plan to upload the plugin to the Dépôt officiel des extensions QGIS you must check that your plugin follows some additional rules, required for plugin Validation.
16.1.2. Writing plugin code
The following section shows what content should be added in each of the files introduced above.
16.1.2.1. metadata.txt
First, the Plugin Manager needs to retrieve some basic information about the
plugin such as its name, description etc. This information is stored in metadata.txt
.
Note
Toutes les métadonnées doivent être encodées en UTF-8.
Nom des métadonnées |
Requis |
Notes |
---|---|---|
name |
Vrai |
une courte chaîne de caractères contenant le nom du plugin |
qgisMinimumVersion |
Vrai |
notation en pointillés de la version minimale de QGIS |
qgisMaximumVersion |
Faux |
notation en pointillés de la version maximale de QGIS |
description |
Vrai |
texte court qui décrit le plugin, pas d” HTML autorisé |
about |
Vrai |
texte plus long qui décrit le plugin en détail, pas de HTML autorisé |
version |
Vrai |
chaîne courte avec la notation en pointillés de la version |
author |
Vrai |
nom de l’auteur |
Vrai |
e-mail de l’auteur, uniquement affiché sur le site web pour les utilisateurs connectés, mais visible dans le gestionnaire de plugin après l’installation du plugin |
|
changelog |
Faux |
de type texte, indique les modifications de version. Peut être multiligne, le HTML n’est pas autorisé |
experimental |
Faux |
booléen, |
deprecated |
Faux |
booléen, |
les mots-clé |
Faux |
liste séparée par des virgules, les espaces sont autorisés à l’intérieur des balises individuelles |
homepage |
Faux |
une URL valide pointant vers la page d’accueil de votre plugin |
repository |
Vrai |
une URL valide du dépôt du code |
tracker |
Faux |
une URL valide pour le signalement des bugs et demandes |
icon |
Faux |
un nom de fichier ou un chemin d’accès relatif (par rapport au dossier de base du paquet compressé du plugin) d’une image accessible sur le web (PNG, JPEG) |
category |
Faux |
one of |
plugin_dependencies |
Faux |
Une liste de noms séparés par des virgules, des autres extensions à installer. Préférez l’usage du nom tel qu’indiqué dans le champ « nom » des métadonnées de l’extension. |
server |
Faux |
booléen, |
hasProcessingProvider |
Faux |
booléen, |
By default, plugins are placed in the
menu (we will see in the next section how to add a menu entry for your plugin) but they can also be placed into , , , and menus.Une entrée de métadonnées « catégorie » correspondante existe pour le spécifier, de sorte que le plugin peut être classé en conséquence. Cette entrée de métadonnées sert de conseil aux utilisateurs et leur indique où (dans quel menu) se trouve le plugin. Les valeurs autorisées pour « category » sont : Vecteur, Raster, Base de données ou Web. Par exemple, si votre plugin sera disponible à partir du menu « Raster », ajoutez ceci à metadata.txt
.
category=Raster
Note
Si qgisMaximumVersion est vide, il sera automatiquement mis à la version majeure plus .99 lorsqu’il sera téléchargé dans le Dépôt officiel des extensions QGIS.
Un exemple pour ce fichier 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
Ce fichier est requis par le système d’importation de Python. De plus, QGIS exige que ce fichier contienne une fonction classFactory()
, qui est appelée lorsque le plugin est chargé dans QGIS. Elle reçoit une référence à l’instance de QgisInterface
et doit retourner un objet de la classe de votre plugin à partir du mainplugin.py
— dans notre cas, il s’appelle TestPlugin
(voir ci-dessous). Voici à quoi doit ressembler le fichier __init__.py
.
def classFactory(iface):
from .mainPlugin import TestPlugin
return TestPlugin(iface)
# any other initialisation needed
16.1.2.3. mainPlugin.py
C’est là que la magie se produit et c’est à cela que ressemble la magie : (par exemple 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!")
Les seules fonctions de plugin qui doivent exister dans le fichier source du plugin principal (par exemple mainPlugin.py
) sont :
__init__
qui permet l’accès à l’interface de QGISinitGui()
appelé lorsque l’extension est chargéeunload()
appelé lorsque le plugin est déchargé
Dans l’exemple ci-dessus, addPluginToMenu()
est utilisé. Cela ajoutera l’action de menu correspondante au menu . D’autres méthodes existent pour ajouter l’action à un autre menu. Voici une liste de ces méthodes :
Elles ont toutes la même syntaxe que la méthode addPluginToMenu()
.
Il est recommandé d’ajouter votre menu de plugin à l’une de ces méthodes prédéfinies afin de conserver une certaine cohérence dans l’organisation des entrées de plugin. Toutefois, vous pouvez ajouter votre groupe de menus personnalisés directement à la barre de menu, comme le montre l’exemple suivant :
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()
N’oubliez pas de donner à QAction
et QMenu
objectName
un nom spécifique à votre plugin pour qu’il puisse être personnalisé.
While help and about actions can also be added to your custom menu,
a convenient place to make them available is in the
QGIS main pluginHelpMenu()
method.
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
Lorsque vous travaillez sur un véritable plugin, il est judicieux d’écrire le plugin dans un autre répertoire (de travail) et de créer un makefile qui générera des fichiers d’interface utilisateur + de ressources et d’installer le plugin dans votre installation QGIS.
16.1.3. Documenting plugins
La documentation du plugin peut être écrite sous forme de fichiers d’aide HTML. Le module qgis.utils
fournit une fonction, showPluginHelp()
qui ouvrira le navigateur de fichiers d’aide, de la même manière que les autres aides QGIS.
La fonction showPluginHelp()
recherche les fichiers d’aide dans le même répertoire que le module appelant. Elle cherchera, à son tour, index-ll_cc.html
, index-ll.html
, index-en.html
, index-en_us.html
et index.html
, en affichant celui qu’elle trouve en premier. Ici, ll_cc
est la locale QGIS. Cela permet d’inclure plusieurs traductions de la documentation avec le plugin.
La fonction showPluginHelp()
peut également prendre les paramètres packageName, qui identifie un plugin spécifique pour lequel l’aide sera affichée, filename, qui peut remplacer « index » dans les noms des fichiers recherchés, et section, qui est le nom d’une balise d’ancrage html dans le document sur lequel le navigateur sera positionné.
16.1.4. Translating plugins
En quelques étapes, vous pouvez configurer l’environnement pour la localisation du plugin de sorte que, selon les paramètres locaux de votre ordinateur, le plugin sera chargé dans différentes langues.
16.1.4.1. Exigences en matière de logiciels
La façon la plus simple de créer et de gérer tous les fichiers de traduction est d’installer Qt Linguist. Dans un environnement GNU/Linux basé sur Debian, vous pouvez l’installer en tapant: :
sudo apt install qttools5-dev-tools
16.1.4.2. Fichiers et répertoire
Lorsque vous créez l’extension, vous devriez trouver le répertoire « i18n » dans le répertoire principal de l’extension.
Tous les fichiers de traduction doivent être dans ce répertoire.
16.1.4.2.1. Fichier .pro
Premièrement, vous devez créer un fichier « .pro ». Il s’agit d’un fichier projet qui peut être géré par Qt Linguist.
Dans ce fichier « .pro », vous devez spécifier tous les fichiers et formulaires que vous voulez traduire. Ce fichier est utilisé pour mettre en place les fichiers et les variables de localisation. Un fichier projet possible, correspondant à la structure de notre exemple d’extension :
FORMS = ../form.ui
SOURCES = ../your_plugin.py
TRANSLATIONS = your_plugin_it.ts
Votre plugin peut suivre une structure plus complexe, et il peut être réparti sur plusieurs fichiers. Si c’est le cas, gardez à l’esprit que pylupdate5
, le programme que nous utilisons pour lire le fichier pro
et mettre à jour la chaîne traduisible, ne développe pas les caractères génériques, vous devez donc placer chaque fichier explicitement dans le fichier pro
. Votre fichier de projet pourrait alors ressembler à quelque chose comme ceci :
FORMS = ../ui/about.ui ../ui/feedback.ui \
../ui/main_dialog.ui
SOURCES = ../your_plugin.py ../computation.py \
../utils.py
De plus, le fichier your_plugin.py
est le fichier qui appelle tous les menus et sous-menus de votre plugin dans la barre d’outils QGIS et vous voulez les traduire tous.
Enfin, avec la variable « TRANSLATIONS », vous pouvez spécifier les langages de traduction que vous souhaitez.
Avertissement
Assurez-vous de nommer le fichier ts
comme votre_plugin_
+ langue
+ .ts
sinon le chargement de la langue échouera ! Utilisez le raccourci de 2 lettres pour la langue (it pour l’italien, de pour l’allemand, etc…)
16.1.4.2.2. Fichier .ts
Une fois que vous avez créé le .pro
, vous êtes prêt à générer le(s) fichier(s) .ts
pour la (les) langue(s) de votre plugin.
Lancez un terminal, allez au dossier your_plugin/i18n
et saisissez:
pylupdate5 your_plugin.pro
Vous devriez voir le(s) fichier(s) your_plugin_language.ts
.
Ouvrez le fichier .ts
avec Qt Linguist et commencez à traduire.
16.1.4.2.3. Fichier .qm
Lorsque vous avez fini de traduire votre plugin (si certaines chaînes ne sont pas terminées, la langue source de ces chaînes sera utilisée), vous devez créer le fichier .qm
(le fichier .ts
compilé qui sera utilisé par QGIS).
Il suffit d’ouvrir un terminal , de se rendre dans le répertoire your_plugin/i18n
et de taper
lrelease your_plugin.ts
Vous devriez maintenant voir le(s) fichier(s) your_plugin.qm
dans le dossier i18n
.
16.1.4.3. Traduction en utilisant un fichier Makefile
Vous pouvez également utiliser le makefile pour extraire des messages du code python et des dialogues Qt, si vous avez créé votre plugin avec Plugin Builder. Au début du Makefile, il y a une variable LOCALES: :
LOCALES = en
Ajoutez l’abréviation de la langue à cette variable, par exemple pour la langue hongroise: :
LOCALES = en hu
Vous pouvez maintenant générer ou mettre à jour le fichier hu.ts
(et le fichier en.ts
aussi) à partir des sources par: :
make transup
Après cela, vous avez mis à jour le fichier .ts
pour toutes les langues définies dans la variable LOCALES. Utilisez Qt Linguist pour traduire les messages du programme. Pour terminer la traduction, les fichiers « .qm » peuvent être créés par le transcompilateur: :
make transcompile
Vous devez distribuer les fichiers « .ts » avec votre plugin.
16.1.4.4. Chargement de l’extension
Pour voir la traduction de votre plugin, ouvrez QGIS, changez la langue (
) et redémarrez QGIS.Vous devriez voir votre plugin dans la bonne langue.
Avertissement
Si vous changez quelque chose dans votre plugin (nouvelle interface utilisateur, nouveau menu, etc.), vous devez générer à nouveau la version mise à jour des fichiers .ts
et .qm
, donc exécuter à nouveau la commande ci-dessus.
16.1.6. Conseils et Astuces
16.1.6.1. Rechargeur de plugins
Pendant le développement de votre extension, vous aurez fréquemment besoin de la recharger dans QGIS pour la tester. C’est très facile en utilisant l’extension Plugin Reloader. Vous pouvez le trouver via le gestionnaire d’extensions.
16.1.6.2. Automate packaging, release and translation with qgis-plugin-ci
qgis-plugin-ci provides a command line interface to perform automated packaging and deployment for QGIS plugins on your computer, or using continuous integration like GitHub workflows or Gitlab-CI as well as Transifex for translation.
It allows releasing, translating, publishing or generating an XML plugin repository file via CLI or in CI actions.
16.1.6.3. Accès aux extensions
Vous pouvez accéder à toutes les classes des extensions installées depuis QGIS en utilisant python, ce qui peut être pratique pour le débogage.
my_plugin = qgis.utils.plugins['My Plugin']
16.1.6.4. Journal des messages
Les extensions ont leur propre onglet dans le panneau Journal des messages (log).
16.1.6.5. Fichier de ressources
Some plugins use resource files, for example resources.qrc
which define
resources for the GUI, such as icons:
<RCC>
<qresource prefix="/plugins/testplug" >
<file>icon.png</file>
</qresource>
</RCC>
Il est bon d’utiliser un préfixe qui n’entrera pas en collision avec d’autres plugins ou d’autres parties de QGIS, sinon vous risquez d’obtenir des ressources dont vous ne voulez pas. Il vous suffit maintenant de générer un fichier Python qui contiendra les ressources. C’est fait avec la commande pyrcc5 :
pyrcc5 -o resources.py resources.qrc
Note
Dans les environnements Windows, tenter d’exécuter la commande pyrcc5 à partir de l’invite de commande ou de Powershell entraînera probablement l’erreur « Windows ne peut pas accéder au périphérique, au chemin ou au fichier spécifié […] ». La solution la plus simple est probablement d’utiliser le shell OSGeo4W, mais si vous êtes à l’aise pour modifier la variable d’environnement PATH ou pour spécifier explicitement le chemin de l’exécutable, vous devriez pouvoir le trouver à l’adresse <Your QGIS Install Directory>\bin\pyrcc5.exe
.