15
23 sep 2010

Ce billet s'inspire de l'article a simple qgis python tutorial paru sur le blog linfinite. En effet, QGIS offre, depuis la version 1.0, la possibilité de réaliser vos propres extensions en utilisant l'API du logiciel. Mais avant de pouvoir réaliser cela, il est nécessaire de comprendre le rôle des différents éléments. C'est pourquoi, nous détaillerons les étapes nécessaires afin que vous puissiez ensuite réaliser vos propres applications. Mais, comparativement au blog linfinite, notre exemple sera beaucoup plus simple ceci afin d'aller uniquement à l'essentiel.

Génération de la structure du plugin

La création d'un plugin Qgis se fait en langage python. Plutôt que de créer l'ensemble des fichiers nécessaires manuellement, nous allons le faire grâce à un plugin QGIS qui génère un "squelette" de plugin QGIS ! Pour cela, allez dans "Extensions" puis "Installer/Gérer les extensions". Ensuite dans le menu "Paramètres" cochez "Affichez les extensions expérimentales". Enfin, une fois la liste des extensions mises à jour, le "Plugin Builder" devrait être disponible. Installons-le immédiatement et utilisons le immédiatement : menu Extension -> Plugin Builder

plugin_builder_v3.jpg

Une fois le formulaire validé, il vous sera alors proposé d'enregistrer l'architecture de votre plugin avec les différents fichiers. Choisissez le répertoire le répertoire "plugins" qui se trouve dans /home/user/.qgis2/python/plugins/ pour Linux et C:\Users\Nom_Utilisateur\.qgis2\python\plugins pour Windows.

QGIS, au démarrage, scanne le dossier "plugins" et charge alors les différents plugins. il est donc nécessaire de redémarrer QGIS pour qu'il soit pris en compte la première fois.

Pendant le redémarrage de QGIS, regardons les fichiers de notre plugin :

[etienne:/home/etienne/.qgis2/python/plugins/ShowActiveLayer] $ lshelp i18n icon.png __init__.py Makefile metadata.txt plugin_upload.py pylintrc README.html README.txt resources.qrc scripts show_active_layer_dialog_base.ui show_active_layer_dialog.py show_active_layer.py test

Regardons immédiatement ce que fait le nôtre. Pour cela démarrez QGIS et cliquez sur extensions puis Gestionnaire des extensions. Maintenant après avoir tapé "layer" dans le champ de recherche, vous devriez voir le plugin s'afficher. Une fois sélectionné, une nouvelle icône sera automatiquement placée dans votre barre d'outils. Si vous passez votre souris sur le bouton, une infobulle contenant la description de votre plugin s'affichera alors. Pour le moment notre plugin ne fait absolument rien d'autre qu'afficher une fenêtre contenant le bouton "ok" et "cancel". Rien de très extraordinaire ! Néanmoins, avant de commencer à coder, nous allons installer le plugin "reloader". Celui-ci permet de ne pas avoir à fermer puis ouvrir à nouveau QGIS quand vous modifierez votre plugin.

Installation du plugin Reloader

En phase de développement, vous allez effectuer (je l'espère) de nombreuses modifications. Pour éviter d'avoir à redémarrer QGIS à chaque fois nous allons installer le plugin Reloader. Pour cela, allez dans "extensions" puis "Récupérateur des extensions python". Ensuite dans l'onglet "options" cochez "Affichez toutes les extensions, mêmes celles encore expérimentales". Enfin, une fois la liste des extensions mises à jour, le plugin reloader devrait être disponible. Installons-le immédiatement et commençons à le paramétrer.

Si vous tapez la combinaison de touches alt+F5, une fenêtre vous demandant de sélectionner le plugin que vous souhaitez recharger automatiquement apparaît. Sélectionnez "showactivelayer". Maintenant, à chaque fois que vous appuierez sur la touche F5, celui-ci se rechargera automatiquement. Faisons le test immédiatement et modifions le texte qui s'affiche au passage de la souris. Ouvrez le fichier showActiveLayer.py dans .qgis/python/plugins/. Ensuite, ajoutez par exemple un point d'exclamation à la fin de la phrase "Show Active Layer". Retournez maintenant à QGIS et appuyez sur F5. Le texte est alors automatiquement mis à jour.

Maintenant, que nous disposons des bases nécessaires, explorons un peu l'API de QGIS et surtout commençons concrètement à créer notre plugin.

A la découverte de l'API de QGIS

L'API de QGIS est riche, vous pourrez, à travers les différentes classes (plus d'une centaine), accéder à la totalité des composants du logiciel. Avant de commencer concrètement à créer notre plugin attardons-nous un peu sur celle-ci. Vous verrez ce n'est pas du temps perdu car vous aurez très souvent recours à l'API. C'est en quelque sorte votre encyclopédie des méthodes et des attributs du logiciel.

Pour commencer, nous allons utiliser la console python disponible dans QGIS. Pour cela, une fois votre logiciel démarré et une couche chargée, allez dans extensions et sélectionnez Console python. Une nouvelle fenêtre devrait alors s'ouvrir. Nous allons maintenant effectuer quelques opérations de bases afin de nous familiariser avec l'API :

>>> mapCan = qgis.utils.iface.mapCanvas() >>> mapCan.layerCount() 1 >>> lay = mapCan.layer(0) >>> print lay.name() TM_WORLD_BORDERS-0.3 >>> lay.setLayerName("World Border") >>> print lay.name() World Border

La classe principale que vous manipulerez le plus souvent est mapCanvas. Celle-ci est votre porte d'entrée vers les différents composants relatifs à la carte. Je vous conseille de vous y attarder, elle vous sera certainement très utile plus tard. Mais bon, trêve de bavardage passons maintenant à notre plugin.

Création du plugin

Allez, vous devez avoir les doigts qui vous démangent non ? Alors commençons sans plus attendre ! La création d'un plugin se divise en deux niveaux. Le premier qui peut être accessoire, est le design de l'interface graphique. Le second consiste à implémenter concrètement ce que devra réaliser notre future application.

Création de l'interface

Deux solutions s'offrent à vous. Soit modifier le fichier UI_NomDuPlugin.py en y ajoutant les différents que vous souhaitez, ou utiliser le programme QT Designer. Ce dernier permet de dessiner vos éléments puis de générer ensuite le code correspondant. C'est cette seconde alternative que nous choisirons, pour des raisons évidentes de simplicité. La démarche de création est facilitée du fait qu'à l'intérieur de votre répertoire se trouve un fichier Ui_NomDuPlugin.ui. C'est ce format qui est utilisé par QT Designer. Ainsi, une fois ce dernier démarré, sélectionner le fichier portant l'extension .ui.

list_view_new.png

Voilà une fois nos différents éléments placés comme nous le souhaitons, il va falloir compiler notre fichier xml Ui_NomDuPlugin.ui. Cela se passe en ligne de commande de la manière suivante :

pyuic4 -o tmp.py -x Ui_showActiveLayer.ui Par sécurité j'ai préféré créer un fichier temporaire nommé tmp.py plutôt que d'écraser UI_NomDuPlugin.py. J'ouvre maintenant ces deux fichiers dans mon éditeur de texte et je remplace les éléments de UI_NomDuPlugin.py par les éléments de tmp.py. J'obtiens maintenant le code suivant : from PyQt4 import QtCore, QtGui class Ui_showActiveLayer(object): def setupUi(self, showActiveLayer): showActiveLayer.setObjectName("showActiveLayer") showActiveLayer.resize(389, 279) self.buttonBox = QtGui.QDialogButtonBox(showActiveLayer) self.buttonBox.setGeometry(QtCore.QRect(30, 240, 341, 32)) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.plainTextEdit = QtGui.QPlainTextEdit(showActiveLayer) self.plainTextEdit.setGeometry(QtCore.QRect(10, 30, 361, 201)) self.plainTextEdit.setObjectName("plainTextEdit") self.label = QtGui.QLabel(showActiveLayer) self.label.setGeometry(QtCore.QRect(10, 10, 181, 17)) self.label.setObjectName("label") self.retranslateUi(showActiveLayer) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), showActiveLayer.accept) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), showActiveLayer.reject) QtCore.QMetaObject.connectSlotsByName(showActiveLayer) def retranslateUi(self, showActiveLayer): showActiveLayer.setWindowTitle(QtGui.QApplication.translate("showActiveLayer", "showActiveLayer", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("showActiveLayer", "Les couches actives sont :", None, QtGui.QApplication.UnicodeUTF8)) if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) showActiveLayer = QtGui.QDialog() ui = Ui_showActiveLayer() ui.setupUi(showActiveLayer) showActiveLayer.show() sys.exit(app.exec_())

Et voilà, si vous mettez à jour, dans QGIS, votre plugin (F5), vous verrez que l'interface a été modifiée :

qgis_plugin_show.png

Pour le moment la liste est vide. En effet, notre plugin ne fait absolument rien. Réalisons immédiatement les modifications nécessaires. Cela nous permettra de comprendre concrètement comment fonctionne un plugin, mais cette fois côté code !

Implémentation du code

Dans le dossier showactivelayer vous devez avoir un fichier nommé "showActiveLayer.py". C'est celui-ci que nous utiliserons pour spécifier à Qgis ce qu'il est nécessaire de faire.

Laissons les premières méthodes (__init__, initGui et unload) et intéressons-nous à run(). C'est au sein de celle-ci que se passera l'essentiel de nos actions. Rappelez-vous, nous souhaitons afficher dans notre zone de texte la liste des couches actives. Pour cela nous avons besoin d'un connecteur vers la carte. Cela se fait de la manière suivante :

mapCanvas = self.iface.mapCanvas()

Ensuite, il me suffit de faire une boucle sur les différentes couches de la carte ce qui me permet de créer ma chaîne de caractère que j'incorporerai ensuite à ma zone de texte :

layerName = "" for i in range(mapCanvas.layerCount()-1,-1,-1): layer = mapCanvas.layer(i) layerName += layer.name()+"\n" Et enfin, comme nous l'avons déjà précisé, nous allons ajouter notre chaîne de caractère à notre zone de texte : dlg = showActiveLayerDialog() dlg.ui.plainTextEdit.appendPlainText(layerName)

Et voilà le code complet :

# run method that performs all the real work def run(self): mapCanvas = self.iface.mapCanvas() if mapCanvas.layerCount() == 0: QMessageBox.warning(self.iface.mainWindow(), "Show Active Layer Plugin" , ("No active layer found"), QMessageBox.Ok) return layerName = "" for i in range(mapCanvas.layerCount()-1,-1,-1): layer = mapCanvas.layer(i) layerName += layer.name()+"\n" # create and show the dialog dlg = showActiveLayerDialog() dlg.ui.plainTextEdit.appendPlainText(layerName) dlg.show() result = dlg.exec_() # See if OK was pressed if result == 1: QMessageBox.warning(self.iface.mainWindow(), "Show Active Layer Plugin", ("Voulez allez quitter le plugin !"), QMessageBox.Ok)

Ce qui nous donne donc :

plugin_final.png

Conclusion

L'intérêt technique de ce plugin est très limité. Mais l'objectif était de vous fournir les bases nécessaires ainsi que les différentes ressources disponibles afin que vous puissiez ensuite réaliser vos propres applications. J'espère ainsi que ce billet vous aura permis de vous familiariser avec cet environnement de développement. L'API de Qgis, riche et complète, offre tous les éléments nécessaires afin que vous puissiez laisser libre cours à votre imagination alors n'hésitez pas à la découvrir vous même et à réaliser vos propres applications.

Ressources

img_slideshow: 
A propos de l'auteur: 
GeoTribu

Toute l'actualité de la géomatique Open Source ! Mais aussi des tutoriels, des billets de blog, des tests et surtout une bonne humeur géographique !

Commentaires

Une excellente introduction qui donne envie d'aller encore plus loin ;) merci :)

Merci beaucoup excellente introduction!!

Je vous remercie pour vos encouragements :)
Cela fait toujours plaisir.

Arnaud

Bonjour,

je me lance dans la réalisation de plugin avec Qgis Enceladus

J'ai suivi le tutoriel ici: http://www.geotribu.net/node/284
Mon dossier de plugins est ici: C:\Utilitaires\Quantum GIS Enceladus\python\plugins
Et tout se charge bien dans Enceladus.

J'ai utilisé Qt Designer pour créer une interface où:
- il y a un fichier raster à renseigner avec un bouton ouvrant une fenêtre de sélection
- un fichier vecteur à renseigner avec un bouton ouvrant une fenêtre de sélection
- Une action à engager qui appelle Fwttools (bien entendu sur des fonctions non enregistrées dans Qgis à l'origine.) avec en paramètre les 2 fichiers ci-dessus.

Bien entendu à chaque bouton je dois engager les actions citées au-dessus mais je n'y suis pas encore

En effet je bloque sur l'étape suivante du tutoriel où j'ai une erreur de syntaxe dans la console python de Qgis.

pyuic4 -o tmp.py -x Ui_showActiveLayer.ui

Bien sur ensuite je n'ai pu affecter les actions nécessaires à mes boutons si cette étape n'est pas franchie.
Toute aide est la bienvenue sur ce sujet pour cette étape comme pour les suivantes.

AUtre solution essayée :

J'ai installé sinon python27 et PyQT4 (ici: http://www.riverbankcomputing.co.uk/software/pyqt/download ). Bien entendu, j'ai mis mon fichier à modifier dans la racine de python27

ET j'ai le même problème de syntaxe.

J'ai aussi utilisé la 2e formule possible à savoir:
-----------------

Citation :

pyuic Ui_showActiveLayer.ui > Ui_showActiveLayer.py

-----------------

Et toujours l'erreur de syntaxe

Bonjour,

Je ne pense pas que la compilation du fichier avec pyuic puisse se faire dans la console de QGIS.
Essayez avec un bash.

Arnaud

J'ai essayé avec python.exe (en ayant au préalable installé PYTHON2.7 et PYQT4)
J'ai le même problème de syntaxe

il faut au préalable que tu places dans le répertoire où se trouve le fichier pyuic.exe et là tu lances la ligne de commande pyuic test.ui>test.py

J'ai mis mon fichier ici :
C:\Python27\Lib\site-packages\PyQt4

où se trouve pyuic4.bat

J'ai lancé la commande python.exe et y ai inscrit:

pyuic Ui_showActiveLayer.ui > Ui_showActiveLayer.py

identiquement j'ai le résultat suivant:
File "",line 1
pyuic Ui_showActiveLayer.ui > Ui_showActiveLayer.py

SyntaxError Invalid syntax

J'ai ensuite inscrit la formule
pyuic4-o tmp.py -x Ui_showActiveLayer.ui

Même problème.

Le problème semble provenir de votre fichier source.
Commencez par essayer de faire un fichier le plus simple possible et voir si ça fonctionne.

Arnaud

Je ne sais pas si vous bloquez toujours sur ce point. Je viens de rencontrer le même problème et je l'ai résolu en placant temporairement le xxxx.ui dans le dossier où se trouve pyuic4.bat
et en renseignant correctement le PYTHONPATH (qui n'avait pas été créé).

Une fois ces deux choses faites, tout marche.

Eric

Merci pour ces éclaircissements. Ne fonctionnant pas sur Windows, c'est toujours bon des retours.

Arnaud

Bonjour,

tout d'abord je tiens à vous remercier pour ce tutoriel qui m'a pas mal éclairé sur l'utilisation et la création des plugins. Malheureusement, lorsque j'ai voulu à mon tour m'y mettre, c'est tout de suite devenu plus compliqué. Je suis sous la version 1.6 de QGIS.

J'ai commencé par installé le plugin "Plugin Builder" puis j'ai remplis les champ texte à renseigner comme dans votre exemple. j'ai ensuite sauvegardé sur C:\Documents and Settings\user\.qgis\python\plugins\showactivelayer.

Voila la réponse que j'obtiens:

Plugin Builder Results

Your plugin test was created in:
C:/Documents and Settings/user/.qgis/python/plugins\test
Your QGIS plugin directory is located at:
C:/Documents and Settings/user/.qgis/python/plugins

What's Next

Copy the entire directory containing your new plugin to the QGIS plugin directory
Compile the ui file using puic4
Compile the resources file using pyrcc4
Test the plugin by enabling it in the QGIS plugin manager
Customize it by editing the implementation file test.py
Create your own custom icon, replacing the default icon.png
Modify your user interface by opening test.ui in Qt Designer (don't forget to compile it with pyuic4 after changing it)
You can use the Makefile to compile your Ui and resource files when you make changes. This requires GNU make (gmake)

Et impossible de lancer le plugin.

Auriez-vous une solution pour que je puisse continuer votre tutoriel?

Salut

Super tuto que je voulais suivre depuis un moment déjà.
Merci comme toujours ;)

Quelques précisions tout de même :
- Plugin Builder est désormais intégré comme plugin de QGIS téléchargeable via l'installeur de plugins et les dépôts.
- visiblement, les fichiers générés ne fonctionnent pas en l'état et requièrent des traitements/compilations assez fastidieux, rendant l'accès à la création de plugins beaucoup plus difficile aux débutants. Heureusement, on trouve le même générateur ici : http://www.dimitrisk.gr/qgis/creator/ . Après ça rien en change dans le tuto !!
- pour QtDesigner c'est par ici : http://www.riverbankcomputing.co.uk/software/pyqt/download . Une vraie pépite de site web et ses softs d'ailleurs !

Pour le reste tout devrait se dérouler tranquillement ;)

(Julien)

Merci pour ces différentes informations complémentaires.
Il faudrait que je prenne le temps de l'enrichir un peu.

A.

Merci Julien pour avoir compléter les infos de ce tuto très utile.
Je vais pouvoir m'initier au code Python pour les plugins Qgis !

Thomas