2

I have a QGIS plugin which has a combobox (QComboBox) element with a list of layers currently opened in QGIS. The problem is that the layer list is only updated on initialization of the plugin (I do it with QgsMapLayerRegistry method described here), so every layer added afterwards is not listed until I I force plugin reload.

So the question is - how do I implement automatic refresh of current layer list in my combo box? For example, it is clearly implemented in all built-in modules like "Select by location" etc.

There is a workaround here which uses click event on a combobox, but I think there must be a more elegant way.

  • 1
    You can do that by using 'groupRelationsChanged' method of QgsLegendInterface to connect slot. – xunilk Oct 26 '17 at 5:33
2

You can use QgsMapRegistry signals like layersAdded and LayersRemoved. Just connect function that can modify your QComboBox.

Another solution is to use QgsMapLayerComboBox: https://qgis.org/api/classQgsMapLayerComboBox.html I think it should be updated automatically.

  • thank you! QgsMapLayerComboBox worked fine, but now I have to fix .ui headers like you pointed here. I wonder if there is a way to replace all references of QGIS widgets in QtDesigner to qgis.gui so I not need to fix links every time I save .ui file? I may ask it as a new question if you will – Basile Oct 26 '17 at 12:50
  • 1
    I remember that I had this problem on Debian but on my Arch Linux installation everything was fine. I don't know how to fix that. You can always write some kind of script to parse this ui file (it is xml so lxml library is enough) and swap incorrect tags. – dmh126 Oct 26 '17 at 17:20
2

You can do that by using 'groupRelationsChanged' method of QgsLegendInterface to connect slot. Following code snippet is referred to pluging and works as expected:

   .
   .
   .
    def __init__(self, iface):
   .
   .
   .
        self.dlg.comboBox.clear()
        layers = self.iface.legendInterface().layers()
        layer_list = [ layer.name() for layer in layers ]
        self.dlg.comboBox.addItems(layer_list)
   .
   .
   .
    def change_layers(self):
        self.dlg.comboBox.clear()
        layers = self.iface.legendInterface().layers()
        layer_list = [ layer.name() for layer in layers ]
        self.dlg.comboBox.addItems(layer_list)

    def run(self):
        """Run method that performs all the real work"""
        self.iface.legendInterface().groupRelationsChanged.connect(self.change_layers)
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass

Trying it out in my test plugin:

1) With two loaded layers:

enter image description here

2) Adding simultaneously three layers:

enter image description here

enter image description here

3) Removing simultaneously four layers:

enter image description here

enter image description here

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.