Comment puis-je créer et ajouter par programmation des fonctionnalités à une couche mémoire dans QGIS 1.9?

13

J'avais un plugin fonctionnel dans QGIS 1.8 qui lisait les données d'une base de données MSAccess et les ajoutait à une série de couches de mémoire. Il y a un certain traitement impliqué dans l'intérim, donc je ne pense pas que simplement utiliser QGIS pour lire directement à partir de la base de données soit une option.

Je voudrais passer de QGIS 1.8 à 1.9 (principalement en raison de la qualité améliorée du compositeur d'impression). Le plugin ne fonctionne pas avec la nouvelle API.

J'ai essayé une variété de méthodes qui sont apparues dans les recherches Google. Un, en modifiant le code ci-dessous - à partir de http://www.qgis.org/pyqgis-cookbook/vector.html#memory-provider , c'est-à-dire en ajoutant la géométrie et les attributs au fournisseur de données puis en mettant à jour la couche - pour l'adapter à la nouvelle API. un peu mais les attributs n'étaient pas visibles jusqu'à ce que j'entre en mode édition (similaire à http://hub.qgis.org/issues/3713 ). Une approche alternative, détaillée dans la réponse n ° 1 du lien ci-dessus, a ajouté la couche et les attributs correctement, mais je n'ai pas pu ajouter de fonctionnalités à la couche.

Étant donné que cela devrait être une tâche assez simple, j'espère que quelqu'un ici pourra offrir un exemple pratique de la façon dont cela devrait être fait. (PS, je ne suis pas un programmeur professionnel et la plupart de mon codage est assez grossier - je me réjouis de tout conseil, mais je vous demande pardon de votre ignorance)

# Receivers = a list of lists returned from a database query

# create layer
vl = QgsVectorLayer("Point", item, "memory")
pr = vl.dataProvider()

# add fields
pr.addAttributes( [ QgsField("Rec_No", QVariant.Int), QgsField("Include",  QVariant.String), QgsField("Label",  QVariant.String), QgsField("X", QVariant.Double),
                    QgsField("Y", QVariant.Double), QgsField("Z", QVariant.Double), QgsField("Height", QVariant.Double),
                    QgsField("Project_Re", QVariant.String), QgsField("NCA", QVariant.String),
                    QgsField("DayCrit", QVariant.Int), QgsField("EveCrit", QVariant.Int), QgsField("NightCrit", QVariant.Int) ] )

for i in range(len(Receivers)):          
  # add a feature
  fet = QgsFeature()
  X = Receivers[i][3]
  Y = Receivers[i][4]
  fet.setGeometry( QgsGeometry.fromPoint(QgsPoint(X,Y)) )

  # Details = a list of results returned from a database query specific to each result in 'Receivers'

  if Receivers[i][3] != 0:
    Include = 'Yes'
  else:
    Include = 'No'

  fet.setAttributeMap( { 0 : QVariant(Receivers[i][0]), 1 : QVariant(Include), 2 : QVariant(Receivers[i][2]),
                         3 : QVariant(Receivers[i][3]), 4 : QVariant(Receivers[i][4]), 5 : QVariant(Receivers[i][5]), 6 : QVariant(Receivers[i][6]),
                         7 : QVariant(Details[0]), 8 : QVariant(Details[1]), 9 : QVariant(Details[2]), 10 : QVariant(Details[3]), 11 : QVariant(Details[4]) } )
  pr.addFeatures( [ fet ] )

# add a style
vl.loadNamedStyle('C:/OSGeo4W/apps/qgis/python/plugins/Gopher2QGIS/styles/Receiver_Style.qml')

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.commitChanges()
vl.updateExtents()
vl.updateFieldMap()

QgsMapLayerRegistry.instance().addMapLayer(vl)
Adam Bioletti
la source
Jetez un œil au plugin PinPoint. Il ajoute des fonctionnalités avec des attributs à une couche mémoire et fonctionne avec l'API 2.0.
gsherman
Très bien, fonctionne comme un charme. J'ai utilisé cet exemple pour ajouter une couche avec des points d'un service reposant. QGis is great
Peter Venema

Réponses:

8

Merci à gsherman ci-dessus, l'exemple de plugin PinPoint est parfait.

Si je comprends bien, le processus est le suivant:

  1. Créez le calque avec les attributs dans la chaîne de construction
  2. Ajouter ladite couche au registre des cartes
  3. Commencez à éditer sur ce calque
  4. Ajouter des fonctionnalités et valider les modifications

Voici un extrait de mon code qui fonctionne maintenant.

layer =  QgsVectorLayer(
          "Point?field=Rec_No:integer&field=Include:string(120)&field=Label:string(120)&field=X:double&field=Y:double&field=Z:double&field=Height:double&field=Project_Re:string(120)&field=NCA:string(120)&field=DayCrit:integer&field=EveCrit:integer&field=NightCrit:integer",
          item,
          "memory")
QgsMapLayerRegistry.instance().addMapLayer(layer)

# Receivers = as in the above example 'Receivers' is a list of results
for i in range(len(Receivers)):

  # add a feature
  feature = QgsFeature()

  X = Receivers[i][3]
  Y = Receivers[i][4]
  feature.setGeometry( QgsGeometry.fromPoint(QgsPoint(X,Y)) )

  # Details = as in the above example 'Details' is a list of results

  if Receivers[i][1] != 0:
    Include = 'Yes'
  else:
    Include = 'No'

  values = [ QVariant(Receivers[i][0]), QVariant(Include), QVariant(Receivers[i][2]),
                         QVariant(Receivers[i][3]), QVariant(Receivers[i][4]), QVariant(Receivers[i][5]), QVariant(Receivers[i][6]),
                         QVariant(Details[0]), QVariant(Details[1]), QVariant(Details[2]), QVariant(Details[3]), QVariant(Details[4]) ]

  feature.setAttributes(values)
  layer.startEditing()
  layer.addFeature(feature, True)
  layer.commitChanges()
Adam Bioletti
la source
6

Sur la base de la réponse d'Adam Bioletti, d'autres tests du processus décrit montrent que la seule exigence essentielle est de commencer à éditer la couche mémoire avant d' apporter des modifications, telles que la création d'attributs et de fonctionnalités, puis de valider les modifications. Cela peut être fait avant d'ajouter la couche au mappage du registre.

Voici une mise à jour du code du Cookbook qui fonctionne avec l'API 2.0:

# create layer
vl = QgsVectorLayer("Point", "temporary_points", "memory")
pr = vl.dataProvider()

# changes are only possible when editing the layer
vl.startEditing()
# add fields
pr.addAttributes([QgsField("name", QVariant.String),QgsField("age", QVariant.Int),QgsField("size", QVariant.Double)])

# add a feature
fet = QgsFeature()
fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(10,10)))
fet.setAttributes(["Johny", 2, 0.3])
pr.addFeatures([fet])

# commit to stop editing the layer
vl.commitChanges()

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

# add layer to the legend
QgsMapLayerRegistry.instance().addMapLayer(vl)
Jorge Gil
la source