#1 Sat 14 March 2015 20:52
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
QGIS : Creation de Plugin ?
Bonjour,
Je suis élève en Ecole d'ingénieur et j'ai un projet à réaliser sous QGIS. Je dois créer un plugin qui me permettra de faire des requêtes sur des arrêts et lignes de bus (par exemple la charge moyenne à telle heure de la journée de tel arrêt de telle ligne).
J'ai d'abord créé une base de données sous PostGreSQL, qui contient toutes mes données de charge (nombre de personnes dans un bus par rapport à sa capacité d'accueil) à des horaires différents des arrêts d'une ligne donnée.
Puis, j'ai créé avec "Plugin Builder" un plugin, et je l'ai personnalisé grâce à PyQt (pour avoir une interface avec le choix de la ligne, de l'arrêt, de l'heure ...). C'est ici que se pose mon problème.
En effet, je ne vois pas trop comment écrire mon plugin en python pour qu'il aille chercher mes layers dans QGIS et faire les requêtes dont j'ai besoin, et je n'ai pas trouvé de turoriels très clairs sur internet (Si vous en avez sous la main je suis très preneur ). De plus, à chaque fois que je modifie la moindre ligne dans mon plugin, j'ai le message d'erreur suivant qui s'affiche dans QGIS :
Couldn't load plugin Class_remi due an error when calling its classFactory() method
Traceback (most recent call last):
File "C:/PROGRA~1/QGISBR~1/apps/qgis/./pythonqgisutils.py", line 208, in startPlugin
plugins[packageName] = package.classFactory(iface)
File "C:/Users/guyon_000/.qgis2/python/pluginsClass_remi__init__.py", line 34, in classFactory
from .Module_name_remi import Class_remi
File "C:/PROGRA~1/QGISBR~1/apps/qgis/./pythonqgisutils.py", line 460, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
File "C:/Users/guyon_000/.qgis2/python/pluginsClass_remiModule_name_remi.py", line 26, in
import resources
File "C:/PROGRA~1/QGISBR~1/apps/qgis/./pythonqgisutils.py", line 460, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
ImportError: No module named resources
Python version:
2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)]
QGIS version:
2.6.1-Brighton Brighton, e2a51df
Python path: ['C:/PROGRA~1/QGISBR~1/apps/qgis/./python/plugins\processing', 'C:/PROGRA~1/QGISBR~1/apps/qgis/./python', u'C:/Users/guyon_000/.qgis2/python', u'C:/Users/guyon_000/.qgis2/python/plugins', 'C:/PROGRA~1/QGISBR~1/apps/qgis/./python/plugins', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\matplotlib-1.3.1-py2.7-win-amd64.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\nose-1.3.3-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\tornado-4.0.1-py2.7-win-amd64.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\backports.ssl_match_hostname-3.4.0.2-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\certifi-14.05.14-py2.7.egg', 'c:\osgeo4~1\apps\python27\lib\site-packages\python_dateutil-2.1-py2.7.egg', 'c:\osgeo4~1\apps\python27\lib\site-packages\six-1.3.0-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\bin\python27.zip', 'C:\PROGRA~1\QGISBR~1\apps\Python27\DLLs', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\plat-win', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\lib-tk', 'C:\PROGRA~1\QGISBR~1\bin', 'C:\PROGRA~1\QGISBR~1\apps\Python27', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\PIL', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\jinja2-2.7.2-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\markupsafe-0.23-py2.7-win-amd64.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\pytz-2012j-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\win32', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\win32\lib', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\Pythonwin', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\Shapely-1.2.18-py2.7-win-amd64.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\six-1.3.0-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\wx-2.8-msw-unicode', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\xlrd-0.9.2-py2.7.egg', 'C:\PROGRA~1\QGISBR~1\apps\Python27\lib\site-packages\xlwt-0.7.5-py2.7.egg', 'C:\Users\guyon_000\.qgis2\python\plugins\MetaSearch\ext-libs', 'C:\Users\guyon_000\.qgis2\python\plugins\mmqgis/forms', 'C:\PROGRA~1\QGISBR~1\apps\qgis\python\plugins\fTools\tools', 'C:/Users/guyon_000/Desktop/COURS ECN/EI2/Projet']
Merci d'avance pour votre aide!!
Hors ligne
#2 Sun 15 March 2015 16:08
- SANTANNA
- Moderateur
- Lieu: Angers
- Date d'inscription: 18 Jan 2008
- Messages: 3881
Re: QGIS : Creation de Plugin ?
Bonjour,
La raison de cette erreur se trouve formulée ici
Code:
ImportError: No module named resources
Avez-vous pensé à générer le fichier python resources (à l'aide de pyrcc4) comme statué dans le 1/ du fichier Readme du plugin?
Pour ce qui est du développement de l'extension, certains vous diront qu'il vaut mieux se lancer dans une simple écriture de script avant de vouloir en faire un plugin avec interface graphique. Mais quoi qu'il en soit, plusieurs pistes pour avancer:
- la doc de l'API : http://qgis.org/api/2.8/
- le livre de recettes : http://docs.qgis.org/2.6/fr/docs/pyqgis … index.html
- les plugins : installer des plugins proches de ce que vous voulez faire, en décortiquer le contenu et s'en inspirer pour créer le sien
- les moteurs de recherche (ici ou généraux)
EDIT : une autre piste à ne pas négliger tant pour avoir les fonctions que pour déboguer est la Console Python de QGIS. Très pratique.
Dernière modification par SANTANNA (Sun 22 March 2015 19:20)
Hors ligne
#3 Mon 16 March 2015 14:49
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
Re: QGIS : Creation de Plugin ?
Bonjour,
Merci beaucoup pour votre réponse, je vais essayer de continuer mon code grâce à ces documents.
Avez-vous pensé à générer le fichier python resources (à l'aide de pyrcc4) comme statué dans le 1/ du fichier Readme du plugin?
Je n'arrive pas à effectuer la compilation du fichier resources, mais je pense avoir mal compris la méthode : j'ai ouvert une commande windows dans le dossier où se trouve mon plugin, et j'ai écrit: pyrcc4 -o resources.py resources.qrc
En faisant cela, la commande m'indique que "pyrcc4" n'est pas connu, ce qui ne m'étonne pas.
D'autre part, grâce aux documents, j'ai essayé de commencer à coder mon plugin, et une première erreur que je n'arrive pas à expliquer apparaît :
TypeError: QDialog(QWidget parent=None, Qt.WindowFlags flags=0): argument 1 has unexpected type 'QgisInterface'
Voici mon code:
Code:
# To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. __author__ = "guyon_000" __date__ = "$16 mars 2015 15:18:04$" # -*- coding: utf-8 -*- """ /*************************************************************************** Class_remi A QGIS plugin Description_remi ------------------- begin : 2015-03-05 git sha : $Format:%H$ copyright : (C) 2015 by author_remi email : igor.belot@orange.fr ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ # Import the PyQt and QGIS libraries from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * from qgis.utils import * # Initialize Qt resources from file resources.py import resources_rc # Import the code for the dialog from Module_name_remi_dialog import Class_remiDialog import os.path class Class_remi: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir,'i18n','Class_remi_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = Class_remiDialog(self.iface) def initGui(self): # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/Class_remi/icon.png"), "Class_remi", self.iface.mainWindow()) # connect the action to the run method self.action.triggered.connect(self.run) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToVectorMenu("&Class_remi", self.action) def unload(self): # Remove the plugin menu item and icon self.iface.removePluginVectorMenu("&Class_remi", self.action) self.iface.removeToolBarIcon(self.action) def run(self): """Run method that performs all the real work""" # show the dialog self.dlg.init_before_show() self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result == 1: # Do something useful here - delete the line containing pass and # substitute with your code. self.load_line() self.load_arrets() self.test() def load_line(self): uri = QgsDataSourceURI() # set host name, port, database name, username and password uri.setConnection("localhost", "5432", "postgres", "postgres", "210893") # set database schema, table name, geometry column and optionally # subset (WHERE clause) uri.setDataSource("public", "ligne", "geom") vlayer1 = QgsVectorLayer(uri.uri(), "ligne_tan", "postgres") def load_arrets(self): uri = QgsDataSourceURI() # set host name, port, database name, username and password uri.setConnection("localhost", "5432", "postgres", "postgres", "210893") # set database schema, table name, geometry column and optionally # subset (WHERE clause) uri.setDataSource("public", "arrettan", "geom") vlayer2 = QgsVectorLayer(uri.uri(), "arrets_tan", "postgres") def test(self): ligne_tan = self.dlg.ui.Ligne_choix.currentText() arrets_tan = self.dlg.ui.arrets_choix.currentText()
Dernière modification par Spynz (Mon 16 March 2015 17:14)
Hors ligne
#4 Mon 16 March 2015 19:11
- SANTANNA
- Moderateur
- Lieu: Angers
- Date d'inscription: 18 Jan 2008
- Messages: 3881
Re: QGIS : Creation de Plugin ?
En faisant cela, la commande m'indique que "pyrcc4" n'est pas connu, ce qui ne m'étonne pas.
Ça devrait marcher comme cela sauf qu'il faut avoir indiqué le dossier où se trouve pyrcc4 (un des dossiers bin sous C:\QGIS... - désolé, je n'ai pas la version standalone) dans le Path de windows. Sinon, il faudrait indiquer tout le chemin vers pyrcc4.
Pour l'autre point, le numéro de la ligne qui pose problème devrait être dans le message d'erreur. Et si j'ai bien vu, remplacez
Code:
self.dlg = Class_remiDialog(self.iface)
par
Code:
self.dlg = Class_remiDialog()
. En principe ces paramétrages sont configurés par Plugin Builder donc si besoin de les modifier, commentez la ligne existante avant de faire les tests. Ainsi, vous pourrez facilement déboguer.
Hors ligne
#5 Thu 19 March 2015 18:32
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
Re: QGIS : Creation de Plugin ?
Merci beaucoup.
J'ai finalement réussi à ne plus avoir l'erreur avec le resources, en le compilant comme vous me l'avez expliqué. Mais j'ai maintenant un autre problème qui apparaît dès l'ouverture de QGIS :
Code:
NameError: global name 'ui_Class_remi' is not defined
'ui_Class_remi' est appelé dans mon fichier dialog dont le code est le suivant :
Code:
# To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. __author__ = "guyon_000" __date__ = "$16 mars 2015 15:18:04$" # -*- coding: utf-8 -*- """ /*************************************************************************** Class_remiDialog A QGIS plugin Description_remi ------------------- begin : 2015-03-05 git sha : $Format:%H$ copyright : (C) 2015 by author_remi email : igor.belot@orange.fr ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ import os from PyQt4 import QtGui, uic FORM_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'Module_name_remi_dialog_base.ui')) class Class_remiDialog(QtGui.QDialog, FORM_CLASS): def __init__(self, parent=None): """Constructor.""" super(Class_remiDialog, self).__init__(parent) self.ui = ui_Class_remi() self.setupUi(self) self.iface = iface self.settings = QSettings() self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() # selected layer self.vlayer = self.mc.currentLayer() # Clear form self.ui.Ligne_choix.clear() # UI CCONNECTORS self.ui.button_box.accepted.connect(self.run) self.ui.button_box.rejected.connect(self.close) #self.ui.comboBox_inputlayer.currentIndexChanged.connect(self.update_fields) self.ui.Ligne_choix.activated.connect(self.update_fields) self.ui.arrets_choix.activated.connect(self.update_fiels) def init_before_show(self): # Get layers from legend self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() self.ui.Ligne_choix.clear() # Populate comboboxes and fields list_of_vlayers = self.get_useful_layers() if len(list_of_vlayers) > 0: self.ui.Ligne_choix.addItems(list_of_vlayers) self.update_working_layer() self.update_fields() else: self.iface.messageBar().pushMessage("Error", "Plugin needs a valid vector layer loaded.", level=QgsMessageBar.CRITICAL, duration=5) def update_working_layer(self): for layer in self.loaded_layers: if layer.name() == self.ui.Ligne_choix.currentText(): self.vlayer = layer break def get_useful_layers(self): self.vector_line_layers = {} for layer in self.loaded_layers: fields_names = [] # select line vector layers if (layer.type() == layer.VectorLayer) and (layer.geometryType() == QGis.Line): layer_info = [layer] provider = layer.dataProvider() fields = provider.fields() # get vector layer fields for field in fields: if (field.type() == QVariant.Int or field.type() == QVariant.Double): fields_names.append(field.name()) layer_info += [fields_names] self.vector_line_layers[str(layer.name())] = layer_info else: pass vector_line_layers = list(self.vector_line_layers) return vector_line_layers def update_fields(self): self.update_working_layer() def run(self): pass return
Je suis quasiment sûr que cela vient du fait que, même si j'ai pu compiler le fichier resources, je n'ai pas réussi à compiler mon module principal 'Module_name.py'.
J'ai mis en pièce jointe ma compilation et l'erreur qu'elle me renvoit.
Merci d'avance!
Dernière modification par Spynz (Thu 19 March 2015 19:11)
Hors ligne
#6 Thu 19 March 2015 22:14
Re: QGIS : Creation de Plugin ?
Plusieurs choses:
- Si jamais tu as installé QGIS via OSGEO4W: Pour ouvrir la ligne de commande avec un PATH adapté à QGIS (par exemple pour inclure Python ou les outils pyuic4 ou pyrcc4, qui sont installés avec QGIS), tu peux lancer la commande OSGEO4W.bat (qui est installée en même temps que QGIS et accessible via le menu Démarrer).
- Dans ton cas, tu n'as pas besoin de compiler les .ui en .py: L'appel à uic.loadUiType dans ton dialogue s'occupe de charger le .ui dynamiquement au chargement du fichier.
- Pourquoi as-tu ajouté la ligne self.ui = ui_Class_remi() ? Elle ne semble pas nécessaire: Class_remiDialog hérite déjà de la FORM_CLASS (définie dans le .ui). Là où dans le code tu utilises self.ui (par exemple, self.ui.button_box, tu peux remplacer par self (par exemple self.button_box).
- tu as une autre erreur: tu références iface (self.iface=iface) mais il n'y a pas de iface définie localement (peut-être l'ajouter aux arguments du constructeur).
Dernière modification par gvellut (Thu 19 March 2015 22:18)
Hors ligne
#7 Fri 20 March 2015 11:09
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
Re: QGIS : Creation de Plugin ?
Merci pour ta réponse, j'ai réussi à compiler mon fichier .ui mais c'est vrai que je n'en avais pas besoin grâce à la FORM_CLASS. Cela me semble plus correct comme cela:
Code:
# To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. __author__ = "guyon_000" __date__ = "$16 mars 2015 15:18:04$" # -*- coding: utf-8 -*- """ /*************************************************************************** Class_remiDialog A QGIS plugin Description_remi ------------------- begin : 2015-03-05 git sha : $Format:%H$ copyright : (C) 2015 by author_remi email : igor.belot@orange.fr ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ import os from PyQt4 import QtGui, uic from PyQt4 import QtCore from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * from qgis.utils import * FORM_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'Module_name_remi_dialog_base.ui')) class Class_remiDialog(QtGui.QDialog, FORM_CLASS): def __init__(self, iface, parent=None): """Constructor.""" super(Class_remiDialog, self).__init__(parent) self.setupUi(self) self.iface = iface self.settings = QSettings() self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() # selected layer self.vlayer = self.mc.currentLayer() # Clear form self.Ligne_choix.clear() # UI CCONNECTORS self.button_box.accepted.connect(self.run) self.button_box.rejected.connect(self.close) self.Ligne_choix.activated.connect(self.update_fields) self.arrets_choix.activated.connect(self.update_fiels) def init_before_show(self): # Get layers from legend self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() self.Ligne_choix.clear() # Populate comboboxes and fields list_of_vlayers = self.get_useful_layers() if len(list_of_vlayers) > 0: self.Ligne_choix.addItems(list_of_vlayers) self.update_working_layer() self.update_fields() else: self.iface.messageBar().pushMessage("Error", "Plugin needs a valid vector layer loaded.", level=QgsMessageBar.CRITICAL, duration=5) def update_working_layer(self): for layer in self.loaded_layers: if layer.name() == self.Ligne_choix.currentText(): self.vlayer = layer break def get_useful_layers(self): self.vector_line_layers = {} for layer in self.loaded_layers: fields_names = [] # select line vector layers if (layer.type() == layer.VectorLayer) and (layer.geometryType() == QGis.Line): layer_info = [layer] provider = layer.dataProvider() fields = provider.fields() # get vector layer fields for field in fields: if (field.type() == QVariant.Int or field.type() == QVariant.Double): fields_names.append(field.name()) layer_info += [fields_names] self.vector_line_layers[str(layer.name())] = layer_info else: pass vector_line_layers = list(self.vector_line_layers) return vector_line_layers def update_fields(self): self.update_working_layer() def run(self): pass return
J'ai malheureusement toujours une erreur et je n'arrive pas à voir pourquoi (désolé je débute en Python, je fais beaucoup d'erreurs sûrement élémentaires...):
Code:
AttributeError: type object 'QDialog' has no attribute 'mapCanvas'
Hors ligne
#9 Fri 20 March 2015 15:20
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
Re: QGIS : Creation de Plugin ?
Super ça marche!!
Merci beaucoup! Je vais continuer à écrire mon code et reviendrai sur le forum en cas de problème
Hors ligne
#10 Sat 21 March 2015 18:56
- Spynz
- Juste Inscrit !
- Date d'inscription: 14 Mar 2015
- Messages: 6
Re: QGIS : Creation de Plugin ?
Cela fait plusieurs jours que je suis bloqué dans mon code du Plugin. En effet, je n'arrive pas à afficher dans ma comboBox (appelée Ligne_choix) les layers présents dans QGIS.
Voici mon code de dialogue:
Code:
# To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. __author__ = "guyon_000" __date__ = "$16 mars 2015 15:18:04$" # -*- coding: utf-8 -*- """ /*************************************************************************** Class_remiDialog A QGIS plugin Description_remi ------------------- begin : 2015-03-05 git sha : $Format:%H$ copyright : (C) 2015 by author_remi email : igor.belot@orange.fr ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ import os from PyQt4 import QtGui, uic from PyQt4 import QtCore from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * from qgis.utils import * FORM_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'Module_name_remi_dialog_base.ui')) class Class_remiDialog(QtGui.QDialog, FORM_CLASS): def __init__(self, iface, parent=None): """Constructor.""" super(Class_remiDialog, self).__init__(parent) self.setupUi(self) self.iface = iface self.settings = QSettings() self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() # selected layer self.vlayer = self.mc.currentLayer() # Clear form self.Ligne_choix.clear() # UI CCONNECTORS self.button_box.accepted.connect(self.run) self.button_box.rejected.connect(self.close) self.Ligne_choix.activated.connect(self.update_working_layer) self.pushButtonBrowseOutput.clicked.connect(self.output_shp_path) def init_before_show(self): # Get layers from legend self.mc = self.iface.mapCanvas() self.legend = self.iface.legendInterface() self.loaded_layers = self.legend.layers() # Populate comboboxes and fields self.Ligne_choix.clear() list_of_vlayers = self.get_useful_layers() if len(list_of_vlayers) > 0: self.Ligne_choix.addItems(list_of_vlayers) self.update_working_layer() else: self.iface.messageBar().pushMessage("Error", "Plugin needs a valid vector layer loaded.", level=QgsMessageBar.CRITICAL, duration=5) def update_working_layer(self): for layer in self.loaded_layers: if layer.name() == self.Ligne_choix.currentText(): self.vlayer = layer break def get_useful_layers(self): self.vector_line_layers = {} for layer in self.loaded_layers: fields_names = [] # select line vector layers if (layer.type() == QgsMapLayer.VectorLayer) and (layer.geometryType() == QGis.WKBLineString): layer_info = [layer] provider = layer.dataProvider() fields = provider.field() # get vector layer fields for field in fields: if (field.type() == QVariant.Int or field.type() == QVariant.Double): fields_names.append(field.name()) layer_info += [fields_names] self.vector_line_layers[str(layer.name())] = layer_info else: pass vector_line_layers = list(self.vector_line_layers) return vector_line_layers def run(self): pass return def output_shp_path(self): self.lineEdit_outputfile.clear() lastDir = self.settings.value("/LabelLayer/lastDir") self.savelayerPath = QFileDialog.getSaveFileName(None, "Creer un shapefile en sortie", lastDir, "*.shp") if not self.savelayerPath: return self.lineEdit_outputfile.setText(self.savelayerPath) file_info = QFileInfo(self.savelayerPath) self.layer_name = file_info.completeBaseName() self.layer_dir = file_info.absolutePath() self.settings.setValue("/LabelLayer/lastDir", str(self.layer_dir))
Je sélectionne dans "get useful layers" les layers étant des lignes (j'en ai plusieurs d'ouvertes et actives dans QGIS) mais pourtant, je reçois toujours l'erreur
Code:
Error: Plugin needs a valid vector layer loaded.
, erreur que j'ai demandé d'afficher s'il n'y avait aucun layer de géométrie de type ligne.
J'ai essayé plusieurs choses, notamment changer le chargement de mes layers (avec self.iface.legendInterface(), ou avec layers = self.iface.mapCanvas().layers() ...) mais en vain...
Je ne comprends vraiment pas pourquoi ils ne s'affichent pas.
Merci d'avance pour votre aide
Dernière modification par Spynz (Sat 21 March 2015 18:56)
Hors ligne
#11 Sun 22 March 2015 20:10
- SANTANNA
- Moderateur
- Lieu: Angers
- Date d'inscription: 18 Jan 2008
- Messages: 3881
Re: QGIS : Creation de Plugin ?
Bonsoir,
Je ne suis pas non plus expert en Python (et ne l'ai abordé que récemment ayant eu besoin d'un plugin) mais si je puis me permettre quelques conseils...
Pour vérifier le code, un test dans la console Python est assez pratique (J'ai d'ailleurs modifié mon premier message pour y ajouter une nouvelle ressource : la Console Python de QGIS). Faire fréquemment des print (par ex) pour voir ce qui est retourné après quelques lignes permet de bien comprendre le processus et l'avancement du code (il n'y a rien de mieux, je vous assure). Sans oublier que cela permet de faire un code fonctionnel pas forcément dépendant de l'interface (et donc facilement mobilisable dans un autre contexte de script).
Quand je teste la fonction get_useful_layers pas à pas dans la console, ça renvoie "AttributeError: 'QgsVectorDataProvider' object has no attribute 'field' '(mais plutôt fields)" après la ligne fields = provider.field(). C'est peut-être juste une faute de recopie...
Et plus loin, la conversion en liste de vector_line_layers semble poser problème.
Pour déboguer, la doc officielle de QGIS propose également des pistes et comme je l'avais déjà suggéré plus haut, les anciens plugins. vous n'êtes pas le premier à vouloir récupérer dans une liste déroulante des noms de couches. Sans avoir consulté leur code (et ce n'est peut-être pas ce qu'il y a de plus optimisé), je vois que des plugins comme GroupStats, StationLines, DissolvewithStats font quelque chose du genre. Vous y trouverez surement des bouts de code pratique.
Dernière modification par SANTANNA (Sun 22 March 2015 20:38)
Hors ligne