1

i want to change attributes values in a memory layer.

I already asked a similar question but i'm re-stuck on the problem and don't find any solution to this basic need.

Here is what i'm doing so far :

from PyQt4.QtCore import *
from PyQt4.QtGui import * 

vl_r=QgsVectorLayer('Polygon?crs=epsg:2154','population','memory')
pro_r = vl_r.dataProvider()

pro_r.addAttributes([QgsField("name", QVariant.String)])
pro_r.addAttributes([QgsField("pop", QVariant.Int)])

vl_r.updateFields()

QgsMapLayerRegistry.instance().addMapLayer(vl_r)

fet = QgsFeature()
dummy=pro_r.addFeatures([fet])

print(pro_r.capabilitiesString())

attrib={0:'hell',1:666}
dummy=vl_r.dataProvider().changeAttributeValues({fet.id():attrib})
print('Change values : ' + str(dummy))

The value returned by 'dummy' is always True but i never see any change in the attributes table.

When i use a 'normal' layer (stored on disk) the change is made and is immediately visible without any additional command.

What could i be missing ? My code is so simple that i can't see what i forgot ...

Could anybody give me a working sample of attributes change in a memory Layer ?

  • did you try vl_r.changeAttributeValues() ( i.e. without dataProvider() )? You need to call vl_r.startEditing() first. – Matthias Kuhn Nov 16 '15 at 20:43
  • @Matthias Kuhn U mean vl_r.changeAttributeValue() i suppose ? i never find the right syntax ... i tried vl_r.changeAttributeValue(fet.id(),0,'hell') after a vl_r.startEditing (and a vl_r.commitChanges()) but i don't see any change ... fet.setAttributes(['xxx',888]) works for setting the attributes but when it comes to changing attributes values i never find the right solution ... And why wouldn't the first syntax (using the provider) work ? – snaileater Nov 16 '15 at 21:48
  • I wrote about it in the last section here: opengis.ch/2015/04/29/… In short, when you change something directly on the provider, no notifications are emitted. You can also vl_r.updateFeature(fet) if you have a changed feature. – Matthias Kuhn Nov 17 '15 at 8:45
  • @Matthias Kuhn sorry Matthias, i read your article but i didn't find how it was related to my question ... maybe i'm too dumb ... still searching a solution ... i also tried updateFeature but didn't get more result ... – snaileater Nov 19 '15 at 8:25
  • Only the last paragraph "Working with the provider" is slightly related (and not really obvious), I meant to link this one instead: opengis.ch/2015/08/12/with-edit-layer look for where it says "Avoid using the dataProvider() methods!". Quote: "They do not emit internal signals for map redraws and other refreshes of the user interface" [...] like the attribute table. – Matthias Kuhn Nov 19 '15 at 8:37
3

There are basically two problems with the script you posted.

  1. The feature's attributes are not initialized. So the feature itself does not have any attributes (although the provider has). With other providers this would be less of a problem since when saved and retrieved, new features get created, but the memory provider saves the feature as they are.
  2. The feature which you are updating is the one you created and does not yet have an id. The id is generated in the provider when saved. So before changing anything you have to retrieve the feature again with the generated id.

Below the required changes to your script:

from PyQt4.QtCore import *
from PyQt4.QtGui import * 

vl_r=QgsVectorLayer('Polygon?crs=epsg:2154','population','memory')
pro_r = vl_r.dataProvider()

pro_r.addAttributes([QgsField("name", QVariant.String)])
pro_r.addAttributes([QgsField("pop", QVariant.Int)])

vl_r.updateFields()

QgsMapLayerRegistry.instance().addMapLayer(vl_r)

fet = QgsFeature(vl_r.fields())
# Initialize the feature with 2 attributes. You can make this more generic by using layer information instead of a hardcoded number.

dummy=pro_r.addFeatures([fet])

print(pro_r.capabilitiesString())

attrib={0:'hell',1:666}
# Get the (one and only) feature to have an id to work with
fet = vl_r.getFeatures().next()
dummy=vl_r.dataProvider().changeAttributeValues({fet.id():attrib})
print('Change values : ' + str(dummy))
  • Thanks for time spent in answering Matthias ... ! All this remain a bit subtle for me but i will make some other experiments ... – snaileater Dec 1 '15 at 17:17
1

Try with:

attrib={0:'hell',1:str(666)}

For me the second attribute passes only with the str(), even if the QgsField is integer... I think there is a bug with changeAttributeValues() with multiple attributes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.