def test_on_update(self): """Test live update""" layer = QgsVectorLayer("Point?field=age:int", "vl", "memory") # set default value for numbers to [1, {age}], it will depend on the field age and should update field = QgsField('numbers', QVariant.List, 'array') field.setEditorWidgetSetup(QgsEditorWidgetSetup('List', {})) layer.dataProvider().addAttributes([field]) layer.updateFields() layer.setDefaultValueDefinition(1, QgsDefaultValue('array(1, age)', True)) layer.setEditorWidgetSetup(1, QgsEditorWidgetSetup('List', {})) layer.startEditing() form = QgsAttributeForm(layer) feature = QgsFeature(layer.fields()) form.setFeature(feature) form.setMode(QgsAttributeEditorContext.AddFeatureMode) form.changeAttribute('numbers', [12]) form.changeAttribute('age', 1) self.assertEqual(form.currentFormFeature()['numbers'], [1, 1]) form.changeAttribute('age', 7) self.assertEqual(form.currentFormFeature()['numbers'], [1, 7])
class AttributesDock(QgsDockWidget): layerChanged = pyqtSignal(QgsMapLayer) currentValueChanged = pyqtSignal(str, QVariant) def __init__(self, iface): QgsDockWidget.__init__( self, QCoreApplication.translate('AttributesDock', 'Quick Attribution')) self.iface = iface self.widget = QWidget() self.widget.setLayout(QGridLayout()) self.widget.setContentsMargins(0, 0, 0, 0) self.layerComboBox = QgsMapLayerComboBox() self.layerComboBox.layerChanged.connect(self.setLayer) self.layerComboBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.layerTitleLabel = QLabel() self.widget.layout().addWidget(self.layerTitleLabel, 0, 0, 1, 1) self.widget.layout().addWidget(self.layerComboBox, 0, 1, 1, 1) self.formWidget = QWidget() self.formWidget.setLayout(QGridLayout()) self.formWidget.setContentsMargins(0, 0, 0, 0) self.widget.layout().addWidget(self.formWidget, 1, 0, 1, 2) self.setWidget(self.widget) self.attributeForm = None self.layer = None self.feature = None self.layerComboBox.setFilters(QgsMapLayerProxyModel.WritableLayer | QgsMapLayerProxyModel.VectorLayer) QgsProject.instance().readProject.connect(self.onProjectRead) def setLayer(self, layer): if layer == self.layer: return if self.layer: try: self.layer.destroyed.disconnect(self.onLayerRemoved) except TypeError: # Do not care if it is not connected pass self.layer = layer if self.layer: self.layer.destroyed.connect(self.onLayerRemoved) self.layerComboBox.setLayer(layer) if self.attributeForm: try: self.attributeForm.deleteLater() except RuntimeError: # Sometimes the form has already been deleted, that's ok for us pass if self.layer is not None: context = QgsAttributeEditorContext() context.setVectorLayerTools(self.iface.vectorLayerTools()) context.setFormMode(QgsAttributeEditorContext.StandaloneDialog) self.attributeForm = QgsAttributeForm(self.layer, QgsFeature(), context) self.attributeForm.hideButtonBox() try: self.layer.updatedFields.disconnect( self.attributeForm.onUpdatedFields) except TypeError: pass fields = self.layer.fields() self.feature = QgsFeature(fields) for idx in range(self.layer.fields().count()): self.feature.setAttribute(idx, self.layer.defaultValue(idx)) self.feature.setValid(True) self.attributeForm.setFeature(self.feature) self.attributeForm.widgetValueChanged.connect( self.onAttributeChanged) self.formWidget.layout().addWidget(self.attributeForm) self.layerChanged.emit(self.layer) def onLayerRemoved(self): self.setLayer(None) def onAttributeChanged(self, attributeName, value, changed): idx = self.layer.fields().indexOf(attributeName) if value != 'NULL': defaultValue = QgsExpression.quotedValue(value) else: defaultValue = 'NULL' self.layer.blockSignals(True) self.layer.setDefaultValueDefinition(idx, QgsDefaultValue(defaultValue)) self.layer.blockSignals(False) self.currentValueChanged.emit(attributeName, value) def onProjectRead(self, doc): title, isDefined = QgsProject.instance().readEntry( 'quick_attribution', 'layercbxtitle') if isDefined: self.layerTitleLabel.setText(title) else: self.layerTitleLabel.setText(self.tr('Layer'))