{{Outdated}}
Note: This page is VERY outdated, the instructions apply to old versions of QGIS (< 0.8).
- First some background
- Core Plugins
- External Plugins
- Prerequisites
- Plugin Builder Community
- Writing a new external plugin
- Get the plugins module from cvs
- Make sure your qgis.m4 macro is available
- Decide what your plugin needs to do
- Run the plugin builder script
- Test build the plugin
- Modify the default icon
- Modify the GUI
- Implement Plugin Functionality
- 0.8 Revision of this document
- Documentation:
- What are all the files in my generated plugin directory for?
- Getting developer help:
First some background¶
QGIS has a simple plugin mechanism that can be used to add new functionality to QGIS without needing to modify the core source code. Two types of plugins are possible; internal "core" plugins which are part of the standard QGIS build tree and external plugins which have an independent build system and are not part of the normal qgis distribution. Additionally plugins can be written in C++ or Python.
Core Plugins¶
Core plugins should be implemented when the functionality the plugin is cross cutting - offering functionality that is potentially of interest to many users. In addition, core plugins should introduce no new dependencies to the QGIS build environment. If you are doing something that requires a new dependency, consider using the external plugin mechanism outlined below.
External Plugins¶
External plugins, having an independent build system, offer more flexibility - you can introduce new dependencies without impacting on the core QGIS. Also, external plugins are built outside of the QGIS source tree and may be specialised utilities of little use to the general QGIS user population. External plugins that are part of the QGIS cvs are in a separate module called (you guessed it!) 'plugins'.
Prerequisites¶
In order to get any benifit from this tutorial, you will need the following:
- Working knowledge of C++
- Knowledge of Qt would be useful
- Knowledge of Qt Designer
- QGIS 0.2 or better
- An idea for a plugin!
- Probably some knowledge / interest in GIS
Plugin Builder Community¶
There is a Community Website where you can search for and obtain plugins. The build instructions should be included with each plugin. Right enough chit chat! Lets get on with the fun business of writing a new plugin using the plugin builder!
Writing a new external plugin¶
Disclaimer: I chose the subject matter of fishing spots for this tutorial more or less at random. I have no knowledge of fishing other than that it involves long periods of standing around while nothing happens. As such please try to focus on the content of the tutorial rather than my all-too-apparent lack of knowledge of the subject material!
Get the plugins module from cvs¶
To start you will need to ensure you have checked out the separate plugins module because that contains the plugin builder scripts.
For anonymous cvs checkout do:
cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/qgis login cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/qgis co plugins
If you have an existing sourceforge user account you can check out the plugins like this:
export CVS_RSH=ssh cvs -z3 -d:ext:developername@cvs.sourceforge.net:/cvsroot/qgis co plugins
Make sure your qgis.m4 macro is available¶
Your qgis.m4 must be accessible prior to running autogen.sh. The qgis.m4 macro is installed in the share/aclocal subdirectory of your QGIS installation.
You can make qgis.m4 available to your new plugin by creating a symbolic link to /usr/share/aclocal:
ln -s /home/someuser/share/aclocal/qgis.m4 /usr/share/aclocal/
The other option is to edit autogen.sh (see [#testbuild Test build the plugin]).
Decide what your plugin needs to do¶
For this example we will make a simple plugin that fetches the coordinates of fishing locations as listed on http://www.marlinnut.com/latlon.shtml, converts them to shapefile and loads the resulting shape file in the current map view. We will use the qt networking classes to fetch the web page and parse it, and we will use Frank Warmerdam's shapeio tools to create the shapefile.
Run the plugin builder script¶
Next we can run the plugin builder script which will use the plugin template to generate the basics for a new plugin for you:
# ./plugin_builder.pl
Enter the directory name under qgis/plugins/ where your new plugin will be created.
We suggest using a lowercase underscore separated name e.g. clever_plugin Directory for the new plugin:fishing_spots
Enter the name that will be used when creating the plugin library and should be
entered as a mixed case name with no spaces. e.g. CleverPlugin Plugin name: FishingSpots
Enter a short description (typically one line) e.g. The clever plugin does clever stuff in qgis
Plugin description: This is a simple plugin that will create and display a point layer representing fishing spots listed on http://www.marlinnut.com/latlon.shtml.
Enter the name of the application menu that will be created for your plugin Clever Tools
Menu name: Tools
Enter the name of the menu entry (under the menu that you have just defined) that will be used to invoke your plugin. e.g. Clever Plugin Menu item name: Fishing Spots
Summary of plugin parameters:
Plugin directory fishing_spots Name of the plugin: FishingSpots Description of the plugin: This is a simple plugin that will create and display a point layer representing fishing spots listed on http://www.marlinnut.com/latlon.shtml. Menu name: Tools Menu item name: Fishing Spots
Warning - Proceeding will make changes to Makefile.am in this directory, as well as ../configure.in. Please use caution. Create the plugin? [y/n]: y Search pattern not terminated at -e line 1.
Your plugin (FishingSpots) has been created in fishing_spots. To build the plugin, you must change to the top level of the source tree and run ./autogen.sh && ./configure --prefix=$[Whatever your QGISHOME is] && make && make install
Test build the plugin¶
If you follow the instructions on the last line above, and then start QGIS, you will already be able to see your new plugin! (Although it doesnt actually do anything yet).
Note: If you built & installed your qgis into a non-default location, you should edit the autogen.sh file created in your new plugin directory and alter the line for aclocal to include the relative path to your qgis.m4 aclocal dir. For example:
aclocal \
would become
aclocal -I ../../../../share/aclocal/ \
if your install prefix was four directories up from your new plugins directory.
Depending on your system, you may also be able to use the absolute path to the location of the qgis.m4 macro:
aclocal -I /home/someuser/share/aclocal \
Clicking on Tools -> Plugin Manager should show your new plugin the plugin list as shown in the screenie below:
If you check the fishing spots plugin checkbox and press OK, a new menu, menuitem and toolbar icon will be added to the QGIS gui:
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/2_fishing_spots_plugin_icon.png
If you click on the icon, the template generated dialog for your plugin should appear:
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/3_fishing_spots_plugin_default_gui.png
Modify the default icon¶
Now that we know the basic template generated plugin works we can go ahead and start modifying it according to our needs. To start we are going to make a nicer icon. I do this using kiconedit (part of the KDE desktop application suite). If you followed the above steps, the icon will be in fishing_spots/icon.xpm. Open it with kiconeditor (or the GIMP or any other icon editor) and modify it to your taste:
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/4_icon_editing.png
Note: Your icon should be 22x22 pixels!
Now if you try to run make again, you will most likely get an error such as this one:
plugin.cpp: In member function `virtual void Plugin::initGui()': plugin.cpp:83: error: invalid conversion from `char**' to `const char**' plugin.cpp:83: error: initializing argument 1 of `QPixmap::QPixmap(const char**)' plugin.cpp:89: error: invalid conversion from `char**' to `const char**' plugin.cpp:89: error: initializing argument 1 of `QPixmap::QPixmap(const char**)' make[1]: *** [plugin.lo] Error 1 make[1]: Leaving directory `/home/aps02ts/dev/cpp/qgis_plugins/fishing_spots' make: *** [all] Error 2
The reason for this is that the icon editorhas not declared the icon[] array in the xpm file as const. To resolve the problem simply open icon.xpm with your favourite text editor (VIM!). At the top of the file you will see something like this:
/* XPM */
static char *icon[]={
"22 22 134 2",
"Qt c None",
".b c #000000",
"a. c #030202",
.
.
.
Which you should modify like this (adding the 'const' between 'static' and 'char'):
/* XPM */
static const char *icon[]={
"22 22 134 2",
"Qt c None",
".b c #000000",
"a. c #030202",
.
.
.
(Note: if you renamed an existing image to icon.xpm; remeber to change the above static const char *whatevername to icon, otherwise make would complaint about no icon etc.)
Now run make && make install again and the plugin should build successfully. Restart QGIS and you should see your nify new icon in the toolbar:
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/5_fishing_spots_new_icon.png
Modify the GUI¶
Right now we can do (IMHO) the fun bit - designing the gui. In this case I am going to keep it very basic and simply have a a bunch of text boxes with some default values filled in.
Note: We recommend that you use qtdesigner version 3.1 for modifying the dialog in order to ensure backwards compatibility with older versions of QT. If you are unable or unwilling to do this, consider modifying the header in the pluginguibase.ui file - resetting the qt version to 3.1.
So I am going to run designer and then modify the template dialog as shown below. Note that I have also set the dialog icon to use the one we created in the previous step.
I created the side image from my photo collection using the GIMP. Sidebar images should be around 150w x 350h pixels. It would be nice if everyone writing plugins used a similar look and feel with a sideimage left, a main heading, a description box and then the widgets underneath. Of course this is not a prerequisite, and may not be practical in some cases.
My final dialog looks like this:
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/6_fishing_spots_final_dialog.png
Implement Plugin Functionality¶
I am not going to describe this in detail - I refer you to the source for this plugin tutorial which is available in the QGIS plugins module. Rather, I will describe the arrangement of the plugin_template generated classes, and where your modifications should be made.
The default plugin file and directory structure looks like this:
acinclude.m4 aclocal.m4 autogen.sh configure.ac COPYING CVS icon.xpm images INSTALL Makefile.am Makefile.in plugin.cpp pluginguibase.ui pluginguibase.ui.h plugingui.cpp plugingui.h plugin.h README sample_data
http://gallery.qgis.org/cgi-bin/ids/albums/Plugin%20Tutorial/7_fishing_spots_final_output.png
0.8 Revision of this document¶
Note: The following part of theis document is still under construction, and will replace the instructions provided above when complete.
cpp/qgis/src/plugins$ ./plugin_builder.pl
Enter the directory name under qgis/src/plugins/ where your new plugin will be created.
We suggest using a lowercase underscore separated name e.g. clever_plugin
Directory for the new plugin:qgis_community
Enter the name that will be used when creating the plugin library.
The name should be entered as a mixed case name with no spaces. e.g. CleverTool
The plugin name will be used in the following ways:
- it will be 'lower cased' and used as the root of the generated lib name e.g. libqgis_plugin_clevertool
- in its upper cased form it will be used as the basis for class names, in particular CleverToolGuiBase <- The base class for the plugins configuration dialog / gui generated by uic CleverToolGui <- The concrete class for the plugins configuration dialog
- CleverTool <- The class that includes the plugin loader instructions and and calls to your custom application logic
- clevertool.h, clevertool.cpp etc. <- the filenames used to hold the above derived classes Plugin name: QgisCommunity
Enter a short description (typically one line) e.g. The clever plugin does clever stuff in QGIS
Plugin description: This plugin fetches a list of locations of registered QGIS users as a delimited text file and adds it to the map canvas.
Enter the name of the application menu that will be created for your plugin Clever Tools
Menu name: Community
Enter the name of the menu entry (under the menu that you have just defined) that will be used to invoke your plugin. e.g. Clever Plugin Menu item name: Users Map
Summary of plugin parameters:
Plugin directory qgis_community Name of the plugin: QgisCommunity Library name of the plugin: libqgis_plugin_qgiscommunity Description of the plugin: This plugin fetches a list of locations of registered QGIS users as a delimited text file and adds it to the map canvas. Menu name: Community Menu item name: Users Map
Warning - Proceeding will make changes to Makefile.am in this directory, as well as ../../configure.in. Please use caution. Create the plugin? [y/n]: y
Your plugin (QgisCommunity) has been created in qgis_community. Makefile.am and configure.in have been modified. To build the plugin, you must change to the top level of the source tree and run autoreconf, configure, then make.
Once your plugin has successfully built, please see qgis_community/README for hints on how to get started.
Now compile your plugin:
~/dev/cpp/qgis/src/plugins$ make install
After you compile (hopefully successfully) you can enable the plugin using the plugin manager.
This is just a starting point. You now need to modify the code to make it do something useful....read on for a more information to get yourself started.
Documentation:¶
You really need to read the QGIS API Documentation now at:
http://svn.qgis.org/api_doc/html/
In particular look at the following classes:
- QGisInterface : http://doc.qgis.org/classQgisInterface.html
- QGisIface : http://svn.qgis.org/api_doc/html/classQgisIface.html
- QgsMapTool : http://svn.qgis.org/api_doc/html/classQgsMapTool.html
- QgsPlugin : http://svn.qgis.org/api_doc/html/classQgisPlugin.html
QGisIface is an abstract base class (ABC) that specifies what publicly available features of QGIS are exposed to third party code and plugins. QgisInterface is an concrete implementation of this ABC. The preferred way to carry out operations on QGIS is via the QGisInterface. An instance of the QgisInterface is passed to the plugin when it loads. Please consult the QGIS development team if there is functionality required in the QGisInterface that is not available.
QgsPlugin is an ABC that defines required behaviour your plugin must provide. See below for more details.
What are all the files in my generated plugin directory for?¶
Makefile.am
This is the generated Makefile specification for your plugin. You will see that specifies c++ include paths (-I) and library linkages -l) to Qt4, GDAL, GEOS, QGIS Core, QGIS Ui, QGIS Gui and QGis Raster. You should add you application specific dependencies and source files to this Makefile.
qgiscommunity.h
qgiscommunity.cpp
This is the class that provides the 'glue' between your custom application logic and the QGIS application. You will see that a number of methods are already implemented for you - including some examples of how to add a raster or vector layer to the main application map canvas. This class is a concrete instance of the QgisPlugin interface which defines required behaviour for a plugin. In particular, a plugin has a number of static methods and members so that the QgsPluginManager and plugin loader logic can identify each plugin, create an appropriate menu entry for it etc. Note there is nothing stopping you creating multiple toolbar icons and menu entries for a single plugin. By default though a single menu entry and toolbar button is created and its pre-configured to call the run() method in this class when selected. This default implementation provided for you by the plugin builder is well documented, so please refer to the code for further advice.
qgiscommunityguibase.ui
qgiscommunityguibase.ui.h
This is an Abstract Base Class implemented in Qt4 fashion as a Qt designer 'ui' file. It defines the look of the default plugin dialog without implementing any application logic. You can modify this form to suite your needs or completely remove it if your plugin does not need to display a user form (e.g. for custom MapTools).
qgiscommunitygui.cpp
qgiscommunitygui.h
This is the concrete class where application logic for the above mentioned dialog should go. The world is your oyster here really....
qgiscommunity.qrc
This is the Qt4 resources file for your plugin. The Makefile generated for your plugin is all set up to compile the resource file so all you need to do is add your additional icons etc using the simple xml file format. Note the namespace used for all your resources e.g. (":/QgisCommunity/"). It is important to use this prefix for all your resources. We suggest you include any other images and run time data in this resurce file too.
qgiscommunity.png
This is the icon that will be used for your plugin menu entry and toolbar icon. Simply replace this icon with your own icon to make your plugin disctinctive from the rest.
README
This file contains the documentation you are reading now!
Getting developer help:¶
For Questions and Comments regarding the plugin builder template and creating your features in QGIS using the plugin interface please contact us via:
- the QGIS developers mailing list, or
- IRC (#qgis on freenode.net)
QGIS is distributed under the Gnu Public License. If you create a useful plugin please consider contributing it back to the community.