2

Something unexpected is happening within a function connected to pyqt combo box currentIndexChanged event. Two combo boxes are populated and connected to a function to fire upon index change. The function then retrieves specific information from the selected combo box item and populates two other combo boxes respectively.

While all comboboxes are eventually and correctly populated, something is still occurring at the wrong time as I get AttributeError: 'NoneType' object has no attribute pendingFields on the lines indicated in the layerChanged function when the plugin is initially run. After I exit out of the python error warning, the dialog shows up with all comboboxes properly populated. Each time the combobox is used and a new item is selected, the second combobox correctly populates with no errors.

I am wondering if the problem may be related to the moment when combobox items are added--perhaps the currentIndexChanged signal is firing before the first item is added, and therefore is undefined?

The run function upon opening the plugin:

def run(self):
    # show the dialog
    self.dlg.show()

    self.dlg.ui.compteurCombo.clear()
    self.dlg.ui.resCombo.clear()

    layers = QgsMapLayerRegistry.instance().mapLayers().values()

    for layer in layers:
        if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Line:
            self.dlg.ui.resCombo.addItem(layer.name(), layer)
        if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point:
            self.dlg.ui.compteurCombo.addItem(layer.name(), layer)

    self.dlg.ui.vServIn.setMaximum(500000.99)

    # Run the dialog event loop
    result = self.dlg.exec_()
    # See if OK was pressed
    if result == 1:
        # do something useful (delete the line containing pass and
        # substitute with your code)
        self.calcStats()

This is how the comboboxes are connected to the signal and the run function is called.

def initGui(self):
    # Create action that will start plugin configuration
    self.action = QAction(
        QIcon(":/plugins/statsaep/icon.png"),
        u"Calculer statistiques du réseau AEP", 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.addPluginToMenu(u"&statsAEP", self.action)

    QObject.connect(self.dlg.ui.compteurCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
    QObject.connect(self.dlg.ui.resCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)

The function called upon currentIndexChanged:

def layerChanged(self):
    registry = QgsMapLayerRegistry.instance()
    self.comptLayer = self.dlg.ui.compteurCombo.itemData(self.dlg.ui.compteurCombo.currentIndex())
    self.resLayer = self.dlg.ui.resCombo.itemData(self.dlg.ui.resCombo.currentIndex())
    #QMessageBox.information(None, 'Connection result', "Res layer %s" % self.resLayer.name())
#Error occurs here
    comptField_names = [str(field.name()) for field in self.comptLayer.pendingFields()]
#Error also occurs here
    resField_names = [str(field.name()) for field in self.resLayer.pendingFields()]

    self.dlg.ui.consoCombo.clear()
    self.dlg.ui.longCombo.clear()

    for field in comptField_names:
        self.dlg.ui.consoCombo.addItem(field)

    for field in resField_names:
        self.dlg.ui.longCombo.addItem(field)

1 Answer 1

2

Some things to note:

  • You should a more recent style of connecting signals. E.g.:

    QObject.connect(self.dlg.ui.compteurCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
    

    to:

    self.dlg.ui.compteurCombo.currentIndexChanged.connect(self.layerChanged)
    

    (Not sure this applies to QGIS 2.8)


  • In terms of the error you receive, you said "...when the plugin is initially run.". When the plugin is initialised, those comboboxes are likely to be empty which would explain why a NoneType or empty object has no attributes whatsoever. One method could be to use a try; except AttributeError loop so that when the error occurs, it can just be ignored using pass:

    def layerChanged(self):
        try:
            registry = QgsMapLayerRegistry.instance()
            # rest of your code
        except AttributeError:
            pass
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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