Il est possible de créer des extensions dans le langage de programmation Python. Comparé aux extensions classiques développées en C++, celles-ci devraient être plus faciles à écrire, comprendre, maintenir et distribuer du fait du caractère dynamique du langage python.
Les extensions Python sont listées avec les extensions C++ dans le gestionnaire d’extension. Voici les chemins où elles peuvent être situées:
Depuis l’introduction des extensions Python dans QGIS, un certain nombre d’extensions est apparu - sur le wiki du Dépôt des Extensions vous trouverez certaines d’entre elles et vous pourrez utiliser leur source pour en savoir plus sur la programmation avec PyQGIS ou pour savoir si vous ne dupliquez pas des efforts de développement. L’équipe QGIS maintient également un Dépôt officiel des extensions Python. Prêt à créer une extension, mais aucune idée de quoi faire ? Le wiki des Idées d’extensions Python liste les souhaits de la communauté !
Vous pouvez voir ici la structure du répertoire de notre exemple d’extension
PYTHON_PLUGINS_PATH/
MyPlugin/
__init__.py --> *required*
mainPlugin.py --> *required*
metadata.txt --> *required*
resources.qrc --> *likely useful*
resources.py --> *compiled version, likely useful*
form.ui --> *likely useful*
form.py --> *compiled version, likely useful*
A quoi correspondent ces fichiers?
__init__.py = Le point d’entrée de l’extension. Il doit comporter une méthode classFactory() et peut disposer d’un autre code d’initialisation.
mainPlugin.py = Le code principal de l’extension. Contient toutes les informations sur les actions de l’extension et le code principal.
resources.qrc = Le document .xml créé par Qt Designer. Contient les chemins relatifs vers les ressources des formulaires.
resources.py = La traduction en Python du fichier resources.qrc décrit ci-dessus.
form.ui = L’interface graphique créée avec Qt Designer.
form.py = La traduction en Python du fichier form.ui décrit ci-dessus.
metadata.txt = Requis pour QGIS >= 1.8.0. Contient les informations générales, la version, le nom et d’autres métadonnées utilisées par le site des extensions et l’infrastructure de l’extension. A partir de QGIS 2.0, les métadonnées du fichier __init__.py ne seront plus acceptées et le fichier metadata.txt sera requis.
Vous trouverez ici une méthode automatisée en ligne pour créer les fichiers de base (le squelette) d’une classique extension Python sous QGIS.
Il existe également une extension QGIS nommée Plugin Builder qui crée un modèle d’extension depuis QGIS et ne nécessite pas de connexion Internet. C’est l’option recommandée car elle produit des sources compatibles avec la version 2.0.
Ici vous pouvez trouver des informations et des exemples sur ce qu’il faut ajouter dans chacun des fichiers de la structure de fichiers décrite ci-dessus.
Ce fichier est requis par le système d’import de Python. QGIS impose aussi que ce fichier contienne une fonction classFactory() qui est appelée lorsque l’extension est chargée dans QGIS. Elle reçoit une référence vers une instance de la classe QgisInterface et doit renvoyer l’instance de la classe de l’extension située dans le fichier mainplugin.py. Dans notre cas, elle s’appelle TestPlugin (voir plus loin). Voici à quoi devrait ressembler le fichier __init__.py :
def classFactory(iface):
from mainPlugin import TestPlugin
return TestPlugin(iface)
## any other initialisation needed
C’est l’endroit où tout se passe et voici à quoi il devrait ressembler (ex: mainPlugin.py) :
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
# initialize Qt resources from file resources.py
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")
QObject.connect(self.action, SIGNAL("triggered()"), 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
QObject.connect(self.iface.mapCanvas(), SIGNAL("renderComplete(QPainter *)"), 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
QObject.disconnect(self.iface.mapCanvas(), SIGNAL("renderComplete(QPainter *)"), 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 l’extension qui doivent exister dans le fichier source principal de l’extension (ex: mainPlugin.py) sont :
__init__ –> qui donne accès à l’interface de QGIS
initGui() –> appelée lorsque l’extension est chargée.
unload() –> chargée lorsque l’extension est déchargée.
Vous pouvez voir que dans l’exemple ci-dessus, la fonction addPluginToMenu() est utilisée. Elle ajoute l’entrée de menu correspondante au menu . Il existe d’autres méthodes pour ajouter l’action dans un menu différent. Voici une liste de ces méthodes :
- addPluginToRasterMenu()
- addPluginToVectorMenu()
- addPluginToDatabaseMenu()
- addPluginToWebMenu()
Toutes ont la même syntaxe que la méthode addPluginToMenu().
Ajouter votre extension dans un des menus prédéfinis est une méthode recommandée pour conserver la cohérence de l’organisation des entrées d’extensions. Toutefois, vous pouvez ajouter votre propre groupe de menus directement à la barre de menus, 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(":/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")
QObject.connect(self.action, SIGNAL("triggered()"), 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 paramétrer la propriété objectName de QAction et de QMenu avec un nom spécifique à votre extension pour qu’elle puisse être personnalisée.
Vous pouvez voir que dans la fonction initGui(), nous avons utilisé une icône depuis le fichier ressource (appelé resources.qrc dans notre cas)
<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 extensions ou toute autre partie de QGIS sinon vous risquez de récupérer des ressources que vous ne voulez pas. Vous devez juste générer un fichier python qui contiendra ces ressources. Cela peut être fait avec la commande pyrcc4.
pyrcc4 -o resources.py resources.qrc
Note
Dans les environnements Windows, tenter de lancer pyrcc4 en mode commande ou depuis Powershell générera probablement une erreur du type “Windows ne peut pas accéder au périphérique, au répertoire, ou au fichier [...]”. La solution la plus simple est certainement d’utiliser l’environnement OSGeo4W mais si vous vous sentez capable de modifier la variable d’environnement PATH ou de préciser de chemin vers l’exécutable de manière explicite vous devriez pouvoir le trouver dans <Votre répertoire d'installation de QGIS>\bin\pyrcc4.exe.
Et c’est tout ! Rien de bien compliqué :)
Si tout a été réalisé correctement, vous devriez pouvoir trouver et charger votre extension dans le gestionnaire d’extensions et voir un message dans la console lorsque l’icône de barre d’outils ou l’entrée de menu appropriée est sélectionnée.
Lorsque vous travaillez sur une extension réelle, il est sage d’écrire l’extension dans un autre répertoire et de créer un fichier makefile qui générera l’interface graphique et les fichiers ressources en terminant par l’installation de l’extension dans l’installation QGIS.
La documentation sur l’extension peut être écrite sous forme de fichiers d’aide HTML. Le module qgis.utils fournit une fonction, showPluginHelp(), qui ouvrira le fichier d’aide dans un navigateur, de la même manière que pour l’aide de QGIS.
La fonction showPluginHelp() recherche les fichiers d’aide dans le même dossier que le module d’appel. elle recherchera, dans l’ordre, index-ll_cc.html, index-ll.html, index-en.html, index-en_us.html et index.html, affichant celui qu’elle trouve en premier. Ici, ll_cc est pour la locale de QGIS. Ceci permet d’inclure des traductions multiples dans la documentation de l’extension.
La fonction showPluginHelp() prend également les paramètres packageName qui identifie une extension spécifique pour laquelle une aide sera affichée; filename qui peut remplacer “index” dans les noms de fichiers à rechercher; section qui est le nom d’une ancre HTML dans le document où le navigateur doit se positionner.
En peu d’étapes, vous pouvez configurer un environnement pour la traduction de votre extension, de telle sorte que, selon les paramètres de langue de l’ordinateur, l’extension sera chargée dans différentes langues.
La façon la plus facile de créer et gérer les fichiers de traduction est d’installer Qt Linguist. Dans un environnement Linux, cela peut se faire en tapant:
sudo apt-get install qt4-dev-tools
Une fois l’extension créée, vous verrez un dossier i18n à la racine du dossier de l’extension.
Tous les fichiers de traduction doivent être à l’intérieur de ce répertoire.
D’abord, vous devez créer un fichier .pro, qui est un fichier projet que Qt Linguist peut traiter.
Dans ce fichier .pro vous devez préciser tous les fichiers et tous les formulaires que vous voulez traduire. Ce fichier est utilisé pour paramétrer les fichiers et les variables de localisations. Un fichier projet possible, correspondant à la structure de notre :ref:`example plugin<plugin_files_architecture>’:
FORMS = ../form.ui
SOURCES = ../your_plugin.py
TRANSLATIONS = your_plugin_it.ts
Votre extension peut suivre une structure plus complexe, et elle peut être distribuée
Si c’est le cas, gardez en tête que pylupdate4, le programme que nous avons utilisé pour lire le fichier .pro et mettre à jour la chaîne de caractères traduisible, ne développe pas les caractères génériques, vous devez donc placer tous les fichiers explicitement dans le fichier `` .pro``. Votre fichier de projet pourrait ressembler à ceci:
FORMS = ../ui/about.ui ../ui/feedback.ui \
../ui/main_dialog.ui
SOURCES = ../your_plugin.py ../computation.py \
../utils.py
En plus, le fichier your_plugin.py est celui qui appelle tous les menus et sous-menus de votre plugin dans la barre d’outils de QGIS et vous voulez tous les traduire.
Enfin, à l’aide de la variable TRANSLATIONS, vous pouvez spécifier les langues que vous souhaitez en traduction.
Warning
Assurez-vous de nommer le fichier .ts comme combinaison de votre_extension + langue + .ts, sinon, le chargement de la langue échouera! Utilisez un code en 2 lettres pour votre langue (it pour l’Italien; fr pour le Français, etc...)
Une fois le fichier .pro créé, vous êtes en capacité de générer les fichiers .ts pour les différentes langues de votre extension.
Ouvrez un terminal, allez dans le dossier votre_extension/i18n et saisissez:
pylupdate4 your_plugin.pro
vous devriez voir le(s) fichier(s) votre_extension_langue.ts.
Ouvrir le fichier .ts avec Qt Linguist et commencer à traduire.
Une fois la traduction de votre extension finie (si certains textes ne sont pas traduits, ils apparaîtront dans la langue originale), vous devez créer le fichier .qm (la version compilée du fichier .ts qui sera utilisée par QGIS).
Ouvrez un terminal, allez dans le dossier votre_extension/i18n et saisissez:
maintenant, dans le répertoire i18n tu verras les fichiers ton_plugin.qm.
Alternatively you can use the makefile to extract messages from python code and
Qt dialogs, if you created your plugin with Plugin Builder.
At the beginning of the Makefile there is a LOCALES variable:
Add the abbreviation of the language to this variable, for example for
Hungarian language:
Now you can generate or update the hu.ts file (and the en.ts too)
from the sources by:
After this, you have updated .ts file for all languages set in the LOCALES
variable.
Use Qt4 Linguist to translate the program messages.
Finishing the translation the .qm files can be created by the transcompile:
You have to distribute .ts files with your plugin.
Afin d’exécuter la version traduite de votre extension, ouvrez QGIS, modifiez la langue () et redémarrez QGIS.
Vous devriez voir votre extension dans la bonne langue.
Warning
Si vous effectuez une modification dans votre extension (nouvelle interface, nouveau menu, etc...) vous devrez à nouveau exécuter les commandes ci-dessus afin de regénérer des versions actualisées des fichiers .ts et .qm.