Come posso creare e aggiungere programmaticamente funzionalità a un livello di memoria in QGIS 1.9?


13

Avevo un plugin funzionante in QGIS 1.8 che leggeva i dati da un database MSAccess e li aggiungevo a una serie di livelli di memoria. Nel frattempo sono coinvolti alcuni processi, quindi non credo che usare semplicemente QGIS per leggere direttamente dal database sia un'opzione.

Vorrei passare da QGIS 1.8 a 1.9 (principalmente a causa della migliore qualità del compositore di stampa). Il plug-in non funziona con la nuova API.

Ho provato una varietà di metodi che sono emersi nelle ricerche su Google. Uno, modificando il codice seguente - da http://www.qgis.org/pyqgis-cookbook/vector.html#memory-provider , ovvero aggiungendo geometria e attributi al dataprovider e quindi aggiornando il layer - per adattarlo alla nuova API funzionata un po ', ma gli attributi non erano visibili fino a quando non sono entrato in modalità di modifica manualmente (simile a http://hub.qgis.org/issues/3713 ). Un approccio alternativo, dettagliato nella risposta n. 1 del link precedente, ha aggiunto correttamente il livello e gli attributi, ma non sono stato in grado di aggiungere funzionalità al livello.

Dato che dovrebbe essere un compito abbastanza semplice, spero che qualcuno qui possa offrire un esempio funzionante di come dovrebbe essere fatto. (PS Non sono un programmatore professionista e la maggior parte dei miei codici è piuttosto rozza - accolgo con favore qualsiasi consiglio ma chiedo scusa per l'ignoranza da parte mia)

# 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)

Dai un'occhiata al plugin PinPoint. Aggiunge funzionalità con attributi a un livello di memoria e funziona con l'API 2.0.
gsherman,

Molto bene, funziona come un fascino. Ho usato questo esempio per aggiungere un livello con punti da un servizio riposante. QGis è fantastico
Peter Venema il

Risposte:


8

Grazie a gsherman sopra l'esempio del plugin PinPoint è perfetto.

A quanto ho capito il processo è:

  1. Crea il layer con gli attributi nella stringa di costruzione
  2. Aggiungi detto livello al registro delle mappe
  3. Inizia la modifica su quel livello
  4. Aggiungi funzionalità e apporta le modifiche

Ecco un estratto del mio codice che ora funziona.

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()

6

Sulla base della risposta di Adam Bioletti, ulteriori test sul processo descritto mostrano che l'unico requisito essenziale è iniziare a modificare il livello di memoria prima di apportare modifiche, come la creazione di attributi e funzionalità, e quindi eseguire il commit delle modifiche. Questo può essere fatto prima di aggiungere il layer per mappare il registro.

Ecco un aggiornamento del codice del ricettario che funziona con 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.