3

I am creating a plugin using QT Designer and QGIS 2.18. Using Plugin Builder along with examples I have been able to create a combo box that list all current layers in QGIS. I only want to list point layers. From hours of research I keep reading similar threads saying to use custom QT widgets like QgsMapLayerComboBox. But this is where I get confused.

Are these Qgs widgets added into QT Designer in some manner? Or in my script.py directly? Then I read one has to edit the ‘dialog_base.ui’ every time I make change in QT Designer? Can someone lead me on how to filter the combobox below to only view point layers?

Here is my code:

def run(self):
    """Run method that performs all the real work"""
    layers = self.iface.legendInterface().layers()
    layer_list = []
    for layer in layers:
        layer_list.append(layer.name())
    self.dlg.comboBox.addItems(layer_list)


    # show the dialog - this is needed
    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

1 Answer 1

3

I definitely recommend using the QGIS custom widgets. You should have a Qt Designer packaged with your QGIS installation which has these custom widgets available to drag and drop into a dialog like any other Qt widget.

The following is for Windows (I'm not sure about other operating systems).

Start typing Qt into the Windows search bar and select from the results-

enter image description here

Alternatively, you can start Designer with QGIS widgets from the batch file in the bin folder of your installation files:

enter image description here

Drag a QgsMapLayerComboBox into your plugin dialog. I suggest changing the object name to something unique to assist with accessing the correct widgets in your plugin.py file.

enter image description here

In my example I changed the object name to cb_point_layer, so this widget would be accessed with self.dlg.cb_point_layer. Note: A QgsMapLayerComboBox shows all layers loaded in the current project by default, so you don't need to add layer items to it like a regular combo box- you just need to add filters if you wish to limit the layers shown. So to show only point layers you would use:

self.dlg.cb_point_layer.setFilters(QgsMapLayerProxyModel.PointLayer)

Optionally, you can also show the CRS for each layer item in the combo box with:

self.dlg.cb_point_layer.setShowCrs(True)

Also, it is better to add this basic dialog logic to the initGui() method, rather than the run() method- especially if you are making any signal/slot connections. E.g.

def initGui(self):
    """Create the menu entries and toolbar icons inside the QGIS GUI."""

    icon_path = ':/plugins/my_plugin/icon.png'
    self.add_action(
        icon_path,
        text=self.tr(u'Do something...'),
        callback=self.run,
        parent=self.iface.mainWindow())
    self.dlg.cb_point_layer.setFilters(QgsMapLayerProxyModel.PointLayer)
    # optional
    self.dlg.cb_point_layer.setShowCrs(True)

Then, to access the layer selected in the map layer combo box, just use the currentLayer() method. For example, in the run() method:

def run(self):
    """Run method that performs all the real work"""
    # 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.
        point_layer = self.dlg.cb_point_layer.currentLayer()
        # do something with point_layer
4
  • Thank you Ben for such a detailed an easily understandable answer. Felt like I was reading a tutorial! I would add because I am using Python 2.7 there was one additional change needed upon my research, one must also edit the ui file as described in this past post: gis.stackexchange.com/questions/164111/…. Now it is working nicely.
    – Clutch
    Jan 20, 2020 at 21:06
  • @Clutch, glad you got it working. If my answer helped, you could upvote it or accept it.
    – Ben W
    Jan 20, 2020 at 23:47
  • This works for me only if I put self.dlg.cb_point_layer.setFilters() in the run() section, since self.dlg = pluginDialog() is first defined only in the run section and not in initGui. (This is the default in the Plugin Builder)
    – miln40
    Feb 9, 2020 at 15:49
  • Hmm... yes I see. That is the behaviour of new versions of Plugin Builder. Personally I don't care for it! In previous versions, the generated code had self.dlg declared as an instance attribute in the __init__() method. Then all ui setup should be done in initGui() method e.g. signal slot connections, which I prefer. That way you don't have to worry about initializing and setting a First_start variable. Anyway, sounds like you worked it out so all good :)
    – Ben W
    Feb 9, 2020 at 23:25

Your Answer

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

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