Getting started writing QGIS 2.x plugins

This post shows how to quickly and easily create a small QGIS plugin for counting the number of features within a vector layer.

To get started, you will need QGIS and Qt Designer (to design the user interface) installed. If you are on Windows, I suggest WinPython which provides Qt Designer and Spyder (a Python IDE).

The great thing about creating plugins for QGIS: There is a plugin for that! It’s called Plugin Builder. And while you are at it, also install Plugin Reloader. Reloader is very useful for plugin developers because it lets you quickly reload your plugin without having to restart QGIS every time you make changes to the code.

installPluginBuilder

Plugin Builder will create all the files we need for our plugin. Just start it and select a name for your plugin class (one word in CamelCase), as well as a name for the plugin itself and the plugin menu entry (can be multiple words). Once you press Ok, you’re asked to select a folder to store the plugin. You can save directly to the QGIS plugin folder ~\.qgis2\python\plugins.

pluginBuilder

Next, open the newly created folder (in my case ~\.qgis2\python\plugins\BuilderTest). Amongst other files, it contains the user interface file ui_buildertest.ui. Our plugin will count the number of features in a vector layer. Therefore, it needs a combobox which allows the user to select a layer. Open the .ui file in Qt Designer and add a combobox to the dialog. Change the object name of the combobox to layerCombo. We’ll later use this name in the plugin code to add items to the combobox. Save the dialog and close Qt Designer.

qtDesigner

Now, we need to compile the .ui and the resources.qrc file to turn the dialog and the icon into usable Python code. This is done on the command line. On Windows, I suggest using the OSGeo4W Shell. Navigate to the plugin folder and run:

pyuic4 -o ui_buildertest.py ui_buildertest.ui
pyrcc4 -o resources_rc.py resources.qrc

Note: Using the latest version of Plugin Builder, you only need to compile resources.qrc because the .ui is now loaded dynamically. Furthermore, you should use the following command to compile the resources:

pyrcc4 -o resources.py resources.qrc 

If you enable and run the plugin now, you will already see the dialog but the combobox will be empty. To populate the combobox, we need to write a few lines of code in buildertest.py. First, we’ll fetch all loaded layers and add all vector layers to the combobox. Then, we’ll add code to compute and display the number of features in the selected layer. To achieve this, we expand the run() method:

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

    layers = QgsMapLayerRegistry.instance().mapLayers().values()
    for layer in layers:
        if layer.type() == QgsMapLayer.VectorLayer:
            self.dlg.layerCombo.addItem( layer.name(), layer ) 
         
    # Run the dialog event loop
    result = self.dlg.exec_()
    # See if OK was pressed
    if result == 1:
        # do something useful 
        index = self.dlg.layerCombo.currentIndex()
        layer = self.dlg.layerCombo.itemData(index)
        QMessageBox.information(self.iface.mainWindow(),"hello world","%s has %d features." %(layer.name(),layer.featureCount()))

When you are done with the code, you can use Plugin Reloader to load the new version. When you start the plugin now, the combobox will be populated with the names of the vector layers in your current project. And on pressing Ok, the plugin will compute and display the number of features.

builderTEst

builderTestResult

For more information on PyQGIS and more code samples I warmly recommend the PyQGIS Cookbook. Have fun!

16 comments
  1. Curlew said:

    Woah, Thanks for pointing me to this PluginReloader Plugin. The most useful plugin ever. No more countless QGIS restarting sessions

  2. Thank you! Maybe now I’ll be able to update Barry Rowlingson’s epically useful clickfu plugin (currently ≤ 1.8) for newer versions of QGIS.

  3. Hi,

    I tried to follow your article and ran into a nasty problem:

    When compiling the resources file with
    pyrcc4 -o resources.py resources.qrc
    QGis wouldn’t load the plugin but produce an error message, telling that the resources file was not found.

    The solution for me was to use the following command instead:
    pyrcc4 -o resources_rc.py resources.qrc
    This worked.

    Reference for the solution: http://ralsina.me/stories/BBS49.html

    • Thank you for your comment! I updated the post to reflect this. Indeed, I had changed the import from resources_rc to resources in my code but forgot to document that.

      • Just out of curiosity: What needs to be done to change this filename consistently?

      • Which file name?

  4. Stefan Rothe said:

    found it…(Import Directive in the[project].py file was not amended).

    “wer lesen kann ist klar im Vorteil” ;-)

  5. John said:

    In case anyone has trouble finding “Plugin Reloader”, make sure to have “Show also experiment plugins” checked in Plugin Settings. Reload QGIS if necessary after changing the setting.

  6. Kathy said:

    Hello, I tried to follow your article and met a problem when I “reloaded” my plugin “plop” in Qgis :

    “Une erreur est apparue lors de l’exécution du code Python :

    Traceback (most recent call last):
    File “C:/Users/Utilisateur/.qgis2/python/plugins\plop\plop.py”, line 186, in run
    layers = QgsMapLayerRegistry.instance().mapLayers().values()
    NameError: global name ‘QgsMapLayerRegistry’ is not defined

    Version de Python :
    2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)]

    Version de QGIS :
    2.4.0-Chugiak Chugiak, 8fdd08a”

    I tried to declare QgsMapLayerRegistry at the beggining of “plop.py” withy from PyQt4 import QgsMapLayerRegistry, but it’s say “cannot import name QgsMapLayerRegistry”

    What is the problem ?

    Thank you !!!

    • Hi Kathy,
      Please ask this question on the QGIS developer mailing list. Maybe somebody has encountered this problem before. I haven’t.
      Best wishes,
      Anita

      • Kathy said:

        Hi :-)
        Thank you for your answer. I think they gonna kill me because I already post a question about Qt on another problem ^^. But, here we go. I’ll inform you :-)
        Kathy.

      • I think you need to import it from qgis.core

      • Kathy said:

        Yes, it’s that.
        And you need to write “QMessageBox” after “from PyQt4.QtGui import QAction, QIcon” (I found this one alone ^^)

        (I didn’t know there was a Qgis developer mailing list, I think it’s the same thing than the Qgis hub :-S)

        Thank you for your tutorial anyway :-)

  7. farook said:

    Hi.

    I tried similar plugin in qgis2.6.It works fine when there is a layer and throws an error when there is no layer.The error is

    QMessageBox.information(self.iface.mainWindow(),”feature count”,”%s has %d features.” %(layer.name(),layer.featureCount()))
    AttributeError: ‘NoneType’ object has no attribute ‘name’.

    Help would be appreciated.Thanks

    • You need to add error handling.

      • farook said:

        Yeah I debug my code.It works fine when I loaded a layer.And if I remove that added layer and then click the plugin.The qgis crashes writing a .dmp file.