メインページ/QGIS/coding-compilation guide/plugins writing in python/
提供: OSGeo.JP Wiki
% vim: set textwidth=78 autoindent: \section{Writing a QGIS Plugin in Python} % when the revision of a section has been finalized, % comment out the following line: % \updatedisclaimer In this section we provide a beginner's tutorial for writing a simple QGIS Python plugin. It is based on the workshop "Extending the Functionality of QGIS with Python Plugins" held at FOSS4G 2008 by Dr. Marco Hugentobler, Dr. Horst D\"uster and Tim Sutton. Apart from writing a QGIS Python plugin, it is also possible to use PyQGIS from a python command line console which is useful for debugging or writing standalone applications in Python, with their own user interfaces based on the functionality of the QGIS core library. \subsection{Why Python and what about licensing} Python is a scripting language that was designed with the goal of being easy to program. It has a mechanism for automatically releasing memory that is no longer used (garbagge collector). A further advantage is that many programs that are written in C++ or Java offer the possibility to write extensions in Python, e.g. OpenOffice or Gimp. Therefore it is a good investment of time to learn the Python language. PyQGIS plugins take advantage of the functionality of libqgis\_core.so and libqgis\_gui.so. As both libqgis\_core.so and libqgis\_gui.so are licensed under GNU GPL, QGIS Python plugins must also be licenced under the GPL. This means you may use your plugins for any purpose, and you are not forced to publish them. If you do publish them however, they must be published under the conditions of the GPL license. \subsection{What needs to be installed to get started} You will need the following libraries and programs to create QGIS python plugins yourself: \begin{itemize} \item QGIS \item Python >= 2.5 \item Qt \item PyQT \item PyQt development tools \end{itemize} If you use Linux, there are binary packages for all major distributions. For Windows, the PyQt installer contains Qt, PyQt and the PyQt development tools. \subsection{Programming a simple PyQGIS Plugin in four steps}\label{subsec:pyfoursteps} The example plugin demonstrated here is intentionally kept simple. It adds a button to the menu bar of QGIS. When the button is clicked, a file dialog appears where the user may load a shape file. For each python plugin, a dedicated folder that contains the plugin files needs to be created. By default, QGIS looks for plugins in two locations: \$QGIS\_DIR/share/qgis/python/plugins and \$HOME/.qgis/python/plugins. Note that plugins installed in the latter location are only visible for one user. \minisec{Step 1: Make the plugin manager recognise the plugin} Each Python plugin is contained in its own directory. When QGIS starts up it will scan each OS specific subdirectory and initialize any plugins it finds. \begin{itemize} \item \nix{Linux and other unices}:\\ ./share/qgis/python/plugins \\ /home/\$USERNAME/.qgis/python/plugins \item \osx{Mac OS X}:\\ ./Contents/MacOS/share/qgis/python/plugins \\ /Users/\$USERNAME/.qgis/python/plugins \item \win{Windows}:\\ C:\textbackslash Program Files\textbackslash QGIS\textbackslash python\textbackslash plugins \\ C:\textbackslash Documents and Settings\textbackslash\$USERNAME\textbackslash .qgis\textbackslash python\textbackslash plugins \end{itemize} Once that is done, the plugin will show up in the \dropmenuopttwo{mActionShowPluginManager}{Plugin Manager...} To provide the neccessary information for QGIS, the plugin needs to implement the methods \method{name()}, \method{description()}, \method{version()}, \method{qgisMinimumVersion()} and \method{authorName()} which return descriptive strings. The \method{qgisMinimumVersion()} should return a simple form, for example ``1.0``. A plugin also needs a method \method{classFactory(QgisInterface)} which is called by the plugin manager to create an instance of the plugin. The argument of type QGisInterface is used by the plugin to access functions of the QGIS instance. We are going to work with this object in step 2. Note that in contrast to other programing languages, indention is very important. The Python interpreter throws an error if it is not correct. For our plugin we create the plugin folder 'foss4g\_plugin' in \filename{\$HOME/.qgis/python/plugins}. Then we add two new textfiles into this folder, \filename{foss4gplugin.py} and \filename{\_\_init\_\_.py}. The file \filename{foss4gplugin.py} contains the plugin class: \begin{verbatim} # -*- coding: utf-8 -*- # Import the PyQt and QGIS libraries from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * # Initialize Qt resources from file resources.py import resources class FOSS4GPlugin: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface def initGui(self): print 'Initialising GUI' def unload(self): print 'Unloading plugin' \end{verbatim} The file \filename{\_\_init\_\_.py} contains the methods \method{name()}, \method{description()}, \method{version()}, \method{qgisMinimumVersion()} and \method{authorName()} and \method{classFactory}. As we are creating a new instance of the plugin class, we need to import the code of this class: \begin{verbatim} # -*- coding: utf-8 -*- from foss4gplugin import FOSS4GPlugin def name(): return "FOSS4G example" def description(): return "A simple example plugin to load shapefiles" def version(): return "0.1" def qgisMinimumVersion(): return "1.0" def authorName(): return "John Developer" def classFactory(iface): return FOSS4GPlugin(iface) \end{verbatim} At this point the plugin already has the neccessary infrastructure to appear in the QGIS \dropmenuopttwo{mActionShowPluginManager}{Plugin Manager...} to be loaded or unloaded. \minisec{Step 2: Create an Icon for the plugin} To make the icon graphic available for our program, we need a so-called resource file. In the resource file, the graphic is contained in hexadecimal notation. Fortunately, we don't need to worry about its representation because we use the pyrcc compiler, a tool that reads the file \filename{resources.qrc} and creates a resource file. The file \filename{foss4g.png} and the \filename{resources.qrc} we use in this workshop can be downloaded from \url{http://karlinapp.ethz.ch/python\_foss4g}, you can also use your own icon if you prefer, you just need to make sure it is named \filename{foss4g.png}. Move these 2 files into the directory of the example plugin \filename{\$HOME/.qgis/python/plugins/foss4g\_plugin} and enter: \filename{pyrcc4 -o resources.py resources.qrc}. \minisec{Step 3: Add a button and a menu} In this section, we implement the content of the methods \method{initGui()} and \method{unload()}. We need an instance of the class \classname{QAction} that executes the \method{run()} method of the plugin. With the action object, we are then able to generate the menu entry and the button: \begin{verbatim} import resources def initGui(self): # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/foss4g_plugin/foss4g.png"), "FOSS4G plugin", self.iface.getMainWindow()) # connect the action to the run method QObject.connect(self.action, SIGNAL("activated()"), self.run) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginMenu("FOSS-GIS plugin...", self.action) def unload(self): # Remove the plugin menu item and icon self.iface.removePluginMenu("FOSSGIS Plugin...", self.action) self.iface.removeToolBarIcon(self.action) \end{verbatim} \minisec{Step 4: Load a layer from a shape file} In this step we implement the real functionality of the plugin in the \method{run()} method. The Qt4 method \method{QFileDialog::getOpenFileName} opens a file dialog and returns the path to the chosen file. If the user cancels the dialog, the path is a null object, which we test for. We then call the method \method{addVectorLayer} of the interface object which loads the layer. The method only needs three arguments: the file path, the name of the layer that will be shown in the legend and the data provider name. For shapefiles, this is 'ogr' because QGIS internally uses the OGR library to access shapefiles: \begin{verbatim} def run(self): fileName = QFileDialog.getOpenFileName(None,QString.fromLocal8Bit("Select a file:"), "", "*.shp *.gml") if fileName.isNull(): QMessageBox.information(None, "Cancel", "File selection canceled") else: vlayer = self.iface.addVectorLayer(fileName, "myLayer", "ogr") \end{verbatim} \minisec{Signal 'activated ()' in python plugins is deprecated} When writing your python plugin, remember that the \texttt{activated ()} signal of the 'QAction class', used to signal the plugin it has been activated, is deprecated. This signal has disappeared from Qt4 and if Qt4 is not compiled with the Qt3 backward compatibility, it is simply non existent, so no plugin can be called at all. Please replace \texttt{activated ()} with \texttt{triggered ()}. \subsection{Uploading the plugin to the repository} If you have written a plugin you consider to be useful and you want to share with other users you are welcome to upload it to the QGIS User-Contributed Repository. \begin{itemize} \item Prepare a plugin directory containing only the necessary files (ensure that there is no compiled .pyc files, Subversion .svn directories etc). \item Make a zip archive of it, including the directory. Be sure the zip file name is exactly the same as the directory inside (except the .zip extension of course), if not the Plugin Installer will be unable to relate the available plugin with its locally installed instance. \item Upload it to the repository: \url{http://pyqgis.org/admin/contributed} (you will need to register at first time). Please pay attention when filling the form. The Version Number field is especially important, and if filled out incorrectly it may confuse the Plugin Installer and cause false notifications of available updates. \end{itemize} \subsection{Further information} As you can see, you need information from many different sources to a write PyQGIS plugin. Plugin authors need to know Python, the QGIS plugin interface, as well as the Qt4 classes and tools. In the beginning, it is best to learn from examples and copy the mechanism of existing plugins. Using the QGIS plugin installer, which itself is a Python plugin, it is possible to download many existing Python plugins and to study their behaviour. It is also possible to use the on-line Python plugin generator to create a base plugin to work off of. This on-line tool will help you to build a minimal plugin that you can use as a starting point in your development. The result is a ready to install QGIS 1.0 plugin that implements an empty dialog with Ok and Close buttons. It is available here: \url{http://www.pyqgis.org/builder/plugin_builder.py} There is a a collection of on-line documentation that may be useful for PyQGIS programmers: \begin{itemize} \item QGIS wiki: \url{http://wiki.qgis.org/qgiswiki/PythonBindings} \item QGIS API documentation: \url{http://doc.qgis.org/index.html} \item Qt documentation: \url{http://doc.trolltech.com/4.3/index.html} \item PyQt: \url{http://www.riverbankcomputing.co.uk/pyqt/} \item Python tutorial: \url{http://docs.python.org/} \item A book about desktop GIS and QGIS. It contains a chapter about PyQGIS plugin programing: \url{http://www.pragprog.com/titles/gsdgis/desktop-gis} \end{itemize} You can also write plugins for QGIS in C++. See Section \ref{cpp_plugin} for more information about that.