Tutorial 2: Using MapTools with the QGIS Canvas API

Earlier this week I wrote up a simple tutorial showing the useage of the QgsMapCanvas api to create a simple application that loads a shapefile and displays the points in it. But what good is map that you can't interact with? Enter QgsMapTool - the base class for all tools that need to interact with the canvas.

Today I will extend the last tutorial by making it a QMainWindow application with a menu, toolbar and canvas area. The purpose of the tutorial is to provide a demonstrator project, so I wont promise to write the most elegant or robust C++ code. The project will provide 4 toolbar icons for

  • loading a map layer (layer name is hard coded in the application
  • zooming in
  • zooming out
  • panning

The entire project can be checked out form the QGIS Subversion repository using the following command:

svn co https://svn.qgis.org/repos/qgis/trunk/code_examples/2_basic_main_window

In the working directory for the tutorial code you will find a number of files including c++ sources, icons and a simple data file under data. There is also the .ui file for the main window.

Note: You will need to edit the .pro file in the above svn directory to match your system.

Since much of the code is the same as the previous tutorial, I will focus on the MapTool specifics - the rest of the implementation details can be investigated by checking out the project form SVN. A QgsMapTool is a class that interacts with the MapCanvas using the mouse pointer. QGIS has a number of QgsMapTools implemented, and you can subclass QgsMapTool to create your own. In mainwindow.cpp you will see I include the headers for the QgsMapTools near the start of the file:

     30 //
     31 // QGIS Map tools
     32 //
     33 #include "qgsmaptoolpan.h"
     34 #include "qgsmaptoolzoom.h"
     35 //
     36 // These are the other headers for available map tools (not used in this example)
     37 //
     38 //#include "qgsmaptoolcapture.h"
     39 //#include "qgsmaptoolidentify.h"
     40 //#include "qgsmaptoolselect.h"
     41 //#include "qgsmaptoolvertexedit.h"
     42 //#include "qgsmeasure.h"

As you can see, I am only using two types of MapTool subclasses for this tutorial, but there are more available in the QGIS library. Hooking up our MapTools to the canvas is very easy using the normal Qt4 signal/slot mechanism:

     78   //create the action behaviours
     79   connect(mActionPan, SIGNAL(triggered()), this, SLOT(panMode()));
     80   connect(mActionZoomIn, SIGNAL(triggered()), this, SLOT(zoomInMode()));
     81   connect(mActionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOutMode()));
     82   connect(mActionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer()));

Next we make a small toolbar to hold our toolbuttons. Note that the mpAction* actions were created in designer.

     84   //create a little toolbar
     85   mpMapToolBar = addToolBar(tr("File"));
     86   mpMapToolBar->addAction(mpActionAddLayer);
     87   mpMapToolBar->addAction(mpActionZoomIn);
     88   mpMapToolBar->addAction(mpActionZoomOut);
     89   mpMapToolBar->addAction(mpActionPan);

Thats really pretty straightforward Qt stuff too. Now we create our three map tools:

     91   //create the maptools
     92   mpPanTool = new QgsMapToolPan(mpMapCanvas);
     93   mpPanTool->setAction(mpActionPan);
     94   mpZoomInTool = new QgsMapToolZoom(mpMapCanvas, FALSE); // false = in
     95   mpZoomInTool->setAction(mpActionZoomIn);
     96   mpZoomOutTool = new QgsMapToolZoom(mpMapCanvas, TRUE ); //true = out
     97   mpZoomOutTool->setAction(mpActionZoomOut);

Again nothing here is very complicated - we are creating tool instances, each of which is associated with the same mapcanvas, and a different QAction. When the user selects one of the toolbar icons, the active MapTool for the canvas is set. For example when the pan icon is clicked, we do this:

    110 void MainWindow::panMode()
    111 {
    112   mpMapCanvas->setMapTool(mpPanTool);
    113 
    114 }

Conclusion

As you can see extending our previous example into something more functional using MapTools is really easy and only requires a few lines of code for each MapTool you want to provide. I should take a moment here to give Martin Dobias a big thank you for the new and improved MapCanvas (with MapTools) API that is part of the upcoming QGIS 0.8 release! I have various ideas for future tutorials including:

  • how to make your own Qt4 designer mapping widget using libqgis and an extended version of this tutorial
  • how to create your own MapTool subclass
  • how to make a plugin that implements its own MapTools

If you have any strong urge to see a tutorial for one of the above (or something completely different), drop a note in the comments below and Ill see what I can do!


technorati tags:, , , ,

AttachmentSize
mapcanvas_tut2.jpg22.72 KB

Getting Tutorial Code Working with 0.9.1

Hi Tim,

Iv downloaded your tutorial and am trying to get it working with the latest version of QGIS (0.9.1).

Im using OpenSuse 10.3 and have installed the latest version of QGIS with an rpm install.

Now when trying to compile i have been getting the following error:

In file included from main.cpp:19:
/usr/include/qgis/qgsapplication.h:21: error: function definition does not declare parameters

I have used your .pro file which i have edited and included at the bottom of the post.

for the QGISSRCDIR path i have downloaded the QGIS 0.9.1 tarbal, but including this did not help.

Any help will be really appreciated.

thanks in advance
nlev.

/*******************************************************************************************/
TEMPLATE = app
TARGET = qgis_test
QT = qt3support sql opengl network svg gui core xml
LANGUAGE= C++
linux-g++{
QGISDIR=/usr
QGISLIBDIR=$${QGISDIR}/lib
QGISSRCDIR=/home/user/Desktop/qgis_0.9.1/qgis_0.9.1/src
QGISPLUGINDIR=$${QGISLIBDIR}/qgis
DEFINES += QGISPLUGINDIR=$${QGISPLUGINDIR}
LIBS = -L$${QGISLIBDIR} -lqgis_core -lproj -lqgis_gui
}

INCLUDEPATH = $${QGISDIR}/include/qgis \
$${QGISSRCDIR}/core \
$${QGISSRCDIR}/gui \
$${QGISSRCDIR}/plugins \
$${QGISSRCDIR}/providers \
$${QGISSRCDIR}/raster \
$${QGISSRCDIR}/ui

CONFIG += qt gui exceptions stl warn_on debug thread

#RESOURCES += resources.qrc

FORMS += mainwindowbase.ui

HEADERS += mainwindow.h

SOURCES += main.cpp \
mainwindow.cpp
/******************************************************************************/

Update .pro file

Just to answer my own question:

you need to include the following to the .pro file definitions:

DEFINES += QGISPLUGINDIR=$${QGISPLUGINDIR} CORE_EXPORT= GUI_EXPORT=

the CORE_EXPORT is used with windows and left blank with linux in the QGIS CCMake file.

therefore it is just required to be declared and left a null for linux compilations

HOW TO COMPILE QGIS FROM SOURCE CODE FOR WINDOWS

HOW TO COMPILE QGIS FROM SOURCE CODE FOR WINDOWS?

after installation,am nt able to find the src folder from where i hv to run the perl script to add extra plugins...solution???

cn i copy src folder from qgis source code to installed qgis folder..will it work???

plugin building problem

hi,
I hv tried creating new plugin to qgis by follwing steps
1.downloaded qgis 0.8 setup.exe
2.installed qgis
3.run plugin_bulder.pl script
4.created it...but to build it i should run autogen.sh,configure,make
5.before that there must be qgis.m4 in share\aclocal directory as mentioned in tutorial...I DONT HAVE SUCH FILE(QGIS.M4).IS IT BECOZ OF THAT AM NT ABLE TO RUN AUTOGEN.SH...???????
should i download it seperately
my plaform is windows XP..any probs becoz of that?

Beginner - Can't get this code working in Ubuntu Dapper

MUST WORK. I have QGIS 0.7.4 installed and I've added its source file directories (core, gui etc.) to /usr/include/qgis. I changed the project file (2_basic_main_window.pro): QGISDIR=/usr, QGISSRCDIR=/usr/include/qgis and QGISLIBDIR=$${QGISDIR}/lib. I have both qt3 and *qt4 installed.

I installed QGIS0.8 and libqgis0.8_dev0. Now I get many undefined references for libqgis_gui.a. How can I fix this? Which version of QGIS is used for above code?

Any comments will be much appreciated. I really need to get this working soon.

Needs QGIS 0.8

Hi

I'm sorry I should have made it clear that the examples are written for the 0.8 (preview) release so ignore the 0.7.4 stuff on your system.

QGISDIR=[path to installed qgis - should be 0.8 installation path]
QGISLIBDIR=$${QGISDIR}/lib
QGISSRCDIR=[path to qgis/src directory - as checked out from SVN]

Currently you need the full QGIS sources as all the necessary headers arent included in the qgis_dev package.

I havent tested the example with the package based install of 0.8. I suggest installing qgis0.8 from source until such time as its tested and proven to work with the packages. I need to get Steve to work out how to get all the headers included in the dev package first too..

Hope that helps - write back if you have more questions...

Regards

Tim

QGIS Beginner - Can't get this code working in Ubuntu Dapper

Thanks for great tutorial!

I followed the exact steps for Building QGIS [0.7.4] on Ubuntu Step by Step [but replacing Qt3 with Qt4] and installed QGIS 0.8 from svn trunk/qgis tarball.

Now it works:-)

Glad you got it working

Hi

Sorry I didnt get back to your earlier query - I was busy reinstalling my machine...I'm glad you have it working now. Note I updated the step by step notes on the wiki with Dapper specific info.

Regards

Tim