forked from qgis/QGIS-Code-Examples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
482 lines (369 loc) · 18.5 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
Please note: THESE EXAMPLES ARE REALLY OLD AND WILL NOT
Please note: WORK WITH THE CURRENT RELEASE OF QGIS
We provide them here for archive purposes.
QGIS Developer Tutorials
Tim Sutton, 2008
------------------------------------------------------------------------
1. Tutorial 1 - Hello World, QGIS style
2. Working with QgsMapCanvas
3. Working with Labels
------------------------------------------------------------------------
1. Tutorial 1 - Hello World, QGIS style
=======================================
[images/tim50x50.png] Ok so not everyone wants a full blown GIS desktop
application. Sometimes you want to just have a widget inside your application
that displays a map while the main goal of the application lies elsewhere.
Perhaps a database frontend with a map display?
Updated November 2008 to use cmake build system and the updated QGIS 1.0.0 API. Tim
So lets take a little walk through creating a simple mapping widget. It wont do
anything much - just load a shape file and display it in a random colour. But
it should give you an idea of the potential for using QGIS as an embedded
mapping component. Before I carry on, many thanks to Francis Bolduc who wrote
the beginnings of this demo and then came onto IRC today to do some communal
debugging of his prototype. Francis kindly agreed to make his work generally
available - though I've tweaked it a bit to use shapefiles instead of his
original postgis demo.
We start with typical adding the neccessary includes for our app:
//
// QGIS Includes
//
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
#include <qgssinglesymbolrenderer.h>
#include <qgsmaplayerregistry.h>
#include <qgsvectorlayer.h>
#include <qgsmapcanvas.h>
//
// Qt Includes
//
#include <QString>
#include <QApplication>
#include <QWidget>
We use QgsApplication instead of Qt's QApplication, and get some added benifits
of various static methods that can be used to locate library paths and so on.
The provider registry is a singleton that keeps track of vector data provider
plugins. It does all the work for you of loading the plugins and so on. The
single symbol renderer is the most basic symbology class. It renders points,
lines or polygons in a single colour which is chosen at random by default
(though you can set it yourself). Every vector layer must have a symbology
associated with it.
The map layer registry keeps track of all the layers you are using. The vector
layer class inherits from maplayer and extends it to include specialist
functionality for vector data.
Finally the mapcanvas is really the nub of the matter. Its the drawable widget
that our map will be drawn onto.
Now we can move on to initialising our application....
int main(int argc, char ** argv)
{
// Start the Application
QgsApplication app(argc, argv, true);
QString myPluginsDir = "/home/timlinux/apps/lib/qgis";
QString myLayerPath = "/home/timlinux/gisdata/brazil/BR_Cidades/";
QString myLayerBaseName = "Brasil_Cap";
QString myProviderName = "ogr";
So now we have a qgsapplication and we have defined some variables. Since I
tested this on the Ubuntu 8.10, I just specified the location of the vector
provider plugins as being inside the my development install directory. It would
probaby make more sense in general to keep the QGIS libs in one of the standard
library search paths on your system (e.g. /usr/lib) but this way will do for
now.
The next two variables defined here just point to the shapefile I am going to
be using (and you should substitute your own data here).
The provider name is important - it tells qgis which data provider to use to
load the file. Typically you will use 'ogr' or 'postgres'.
Now we can go on to actually create our layer object.
// Instantiate Provider Registry
QgsProviderRegistry::instance(myPluginsDir);
First we get the provider registry initialised. Its a singleton class so we use
the static instance call and pass it the provider lib search path. As it
initialises it will scan this path for provider libs.
Now we go on to create a layer...
QgsVectorLayer * mypLayer =
new QgsVectorLayer(myLayerPath, myLayerBaseName, myProviderName);
QgsSingleSymbolRenderer *mypRenderer = new
QgsSingleSymbolRenderer(mypLayer->geometryType());
QList <QgsMapCanvasLayer> myLayerSet;
mypLayer->setRenderer(mypRenderer);
if (mypLayer->isValid())
{
qDebug("Layer is valid");
}
else
{
qDebug("Layer is NOT valid");
}
// Add the Vector Layer to the Layer Registry
QgsMapLayerRegistry::instance()->addMapLayer(mypLayer, TRUE);
// Add the Layer to the Layer Set
myLayerSet.append(QgsMapCanvasLayer(mypLayer, TRUE));
The code is fairly self explanatory here. We create a layer using the variables
we defined earlier. Then we assign the layer a renderer. When we create a
renderer, we need to specify the geometry type, which do do by asking the
vector layer for its geometry type. Next we add the layer to a layerset (which
is used by the QgsMapCanvas to keep track of which layers to render and in what
order) and to the maplayer registry. Finally we make sure the layer will be
visible.
Now we create a map canvas on to which we can draw the layer.
// Create the Map Canvas
QgsMapCanvas * mypMapCanvas = new QgsMapCanvas(0, 0);
mypMapCanvas->setExtent(mypLayer->extent());
mypMapCanvas->enableAntiAliasing(true);
mypMapCanvas->setCanvasColor(QColor(255, 255, 255));
mypMapCanvas->freeze(false);
// Set the Map Canvas Layer Set
mypMapCanvas->setLayerSet(myLayerSet);
mypMapCanvas->setVisible(true);
mypMapCanvas->refresh();
Once again there is nothing particularly tricky here. We create the canvas and
then we set its extents to those of our layer. Next we tweak the canvas a bit
to draw antialiased vectors. Next we set the background colour, unfreeze the
canvas, make it visible and then refresh it.
// Start the Application Event Loop
return app.exec();
}
In the last step we simply start the Qt event loop and we are all done. Easy as
1-2-3 eh?
This example can be checked out of subversion, compiled and run using cmake
like this:
svn co https://svn.osgeo.org/qgis/trunk/code_examples/1_hello_world_qgis_style
cd 1_hello_world_qgis_style
mkdir build
#optionally specify where your QGIS is installed (should work on all platforms)
#if your QGIS is installed to /usr or /usr/local you can leave this next step out
export LIB_DIR=/home/timlinux/apps
cmake ..
make
./timtut1
When we compile and run it here is what the running app looks like:
[images/tutorial1.jpg]
2. Working with QgsMapCanvas
============================
[images/tim50x50.png]Tutorial 1 showed you 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 our second
tutorial where we show you how to use QgsMapTool - the base class for all tools
that need to interact with the canvas.
**Updated November 2008 to use cmake build system and the updated QGIS 1.0.0
API. Tim**
[images/tutorial2.jpg]
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.osgeo.org/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.
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:
//
// QGIS Map tools
//
#include "qgsmaptoolpan.h"
#include "qgsmaptoolzoom.h"
//
// These are the other headers for available map tools
// (not used in this example)
//
//#include "qgsmaptoolcapture.h"
//#include "qgsmaptoolidentify.h"
//#include "qgsmaptoolselect.h"
//#include "qgsmaptoolvertexedit.h"
//#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:
//create the action behaviours
connect(mActionPan, SIGNAL(triggered()), this, SLOT(panMode()));
connect(mActionZoomIn, SIGNAL(triggered()), this, SLOT(zoomInMode()));
connect(mActionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOutMode()));
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.
//create a little toolbar
mpMapToolBar = addToolBar(tr("File"));
mpMapToolBar->addAction(mpActionAddLayer);
mpMapToolBar->addAction(mpActionZoomIn);
mpMapToolBar->addAction(mpActionZoomOut);
mpMapToolBar->addAction(mpActionPan);
Thats really pretty straightforward Qt stuff too. Now we create our three map
tools:
//create the maptools
mpPanTool = new QgsMapToolPan(mpMapCanvas);
mpPanTool->setAction(mpActionPan);
mpZoomInTool = new QgsMapToolZoom(mpMapCanvas, FALSE); // false = in
mpZoomInTool->setAction(mpActionZoomIn);
mpZoomOutTool = new QgsMapToolZoom(mpMapCanvas, TRUE ); //true = out
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:
void MainWindow::panMode()
{
mpMapCanvas->setMapTool(mpPanTool);
}
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.
You can check out and build this tutorial using SVN and CMake using the
following steps:
svn co https://svn.osgeo.org/qgis/trunk/code_examples/2_basic_main_window
cd 2_basic_main_window
mkdir build
cd build
#optionally specify where your QGIS is installed (should work on all platforms)
#if your QGIS is installed to /usr or /usr/local you can leave this next step out
export LIB_DIR=/home/timlinux/apps
cmake ..
make
./timtut2
A final note
I don't often check the comments on these posts - if you are stuck please
write to the [QGIS Developer mailing list
http://qgis.org/content/view/115/96/"]! Thanks.Tim
3. Working with Labels
======================
[images/tim50x50.png]In my last tutorial I briefly ran through using map tools
to facilitate user interaction with the map canvas. Today we will take a brief
look at labelling features.
Updated November 2008 to use cmake build system and the updated QGIS 1.0.0 API. Tim
[images/tutorial3.jpg]
Before I carry on too far, note that QGIS's automatic labelling algorithm is
very primative. Martin Dobias is planning to implement a much more useful label
placement routine - but its not available at the time of writing this. For the best
label placement results you should defined fields in your attribute table for
position, rotation etc of the label. Since this is only intended to be a 'get
you started' introduction, I won't be doing all that here...
The entire project can be checked out form the QGIS Subversion repository using
the following command:
svn co https://svn.osgeo.org/qgis/trunk/code_examples/3_basic_labelling
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.
Labelling Specifics
If you look in mainwindow.cpp you will notice a couple of new includes
introduced since the last tutorial:
#include <qgslabel.h>
#include <qgslabelattributes.h>
#include <qgsfield.h>
Each vector layer can have a QgsLabel associated with it. A QgsLabel is a
renderer for labels. It has a member of type QgsLabelAttributes which
determines the placement (above / below / left / right etc), rotation, size,
size units (points or map units), font, colour and various other elements of
the label. The QgsField include is needed because we will be querying the
vector layer for its available fields so that we can determine which field
should be used for labelling.
In the same cpp file you will see I define a label and a label attributes
pointer. These will be used to setup the labelling characteristics we want and
then assigned to the layer:
QgsLabel * mypLabel;
QgsLabelAttributes * mypLabelAttributes;
Now we will see how we actually initialise and assign the QgsLabel and the
QgsLabelAttributes to the vector layer.
//
//set up labelling for the layer
//
//get the label instance associated with the layer
QgsLabel * mypLabel;
mypLabel = mypLayer->label();
//and the label attributes associated with the label
QgsLabelAttributes * mypLabelAttributes;
mypLabelAttributes = mypLabel->layerAttributes();
Great now we have a handle on the QgsLabel and QgsLabelAttributes we can start
to manipulate how the label will be displayed. Note that the
mypLabel->layerAttributes() method is poorly named and will likely be changed
(to labelAttributes()) before the final release of QGIS 1.0.
Ok next lets ask the vector layer's data provider what attribute fields it has
so that we can select one to be used for labelling:
//get the field list associated with the layer
//we'll print the names out to console for diagnostic purposes
QgsFieldMap myFields = mypLayer->dataProvider()->fields();
for (unsigned int i = 0; i < myFields.size(); i++ )
{
qDebug("Field Name: " + QString(myFields[i].name()).toLocal8Bit() );
}
By the way - you can browse the code for field, label, label attributes etc
from ["QGIS Source browser"
http://trac.osgeo.org/qgis/browser/trunk/qgis/src/]. Look in the 'core' and
'gui' subdirectories. Also for more implementation examples of how to set up
labelling, it is worth taking a look at [qgslabeldialog.cpp
http://trac.osgeo.org/qgis/browser/trunk/qgis/src/gui/qgslabeldialog.cpp].
With access to the list of fields in your vector layer, you can then for
example present the user with a combo box to select a label field. In this
simple tutorial though I am simply going to use the last field in the attribute
table. Its a bit of a no brainer because our attribute table only has one
field! But at least this way its soft coded...
//just use the last field's name in the fields list as the label field!
qDebug("set label field to " + myFields[myFields.size()-1].name());
mypLabel->setLabelField( QgsLabel::Text, myFields.size()-1);
There are a bunch of other things we can do to manipulate the appearance of the
label. Lets set the text colour to black and draw a yellow 1 point 'halo'
buffer around it so the label won't get lost when there are black features
behind it:
//set the colour of the label text
mypLabelAttributes->setColor(Qt::black);
//create a 'halo' effect around each label so it
//can still be read on dark backgrounds
mypLabelAttributes->setBufferEnabled(true);
mypLabelAttributes->setBufferColor(Qt::yellow);
int myType = QgsLabelAttributes::PointUnits;
mypLabelAttributes->setBufferSize(1,myType);
Finally we need to tell the layer that rendering of labels should be enabled:
mypLayer->enableLabels(true);
For the absolute best labelling results, I advise you to store all the label
properties you can inside your attribute table. Doing this will allow you to
set rotation, placement etc on a per label basis. I left some comments in the
tutorial source code that will get you started with this:
/*
* Here are a bunch of other things you can set based on values on a database field
* the second parameter in each case would be the field name from which the
* attribute can be retrieved.
mypLabel->setLabelField( QgsLabel::Family, "fontFamily" );
mypLabel->setLabelField( QgsLabel::Bold, "fontIsBold" );
mypLabel->setLabelField( QgsLabel::Italic, "fontIsItalic" );
mypLabel->setLabelField( QgsLabel::Underline, "fontIsUnderlined" );
mypLabel->setLabelField( QgsLabel::Size, "fontSize" );
mypLabel->setLabelField( QgsLabel::BufferSize,"fontBufferSize" );
mypLabel->setLabelField( QgsLabel::XCoordinate, "labelX" );
mypLabel->setLabelField( QgsLabel::YCoordinate, "labelY");
mypLabel->setLabelField( QgsLabel::XOffset, "labelXOffset");
mypLabel->setLabelField( QgsLabel::YOffset, "labelYOffset");
mypLabel->setLabelField( QgsLabel::Alignment, "labelAlignment" );
mypLabel->setLabelField( QgsLabel::Angle, "labelAngle");
*/
Well that wraps up this tutorial. One thing I noticed is that the canvas is not
refreshing properly sometimes on the mac unless you cover the application
briefly with another window. Ill post an update here if I figure out what is
causing this.
You can check out and build this tutorial using SVN and CMake using the
following steps:
svn co https://svn.osgeo.org/qgis/trunk/code_examples/3_basic_labelling
cd 3_basic_labelling
mkdir build
cd build
#optionally specify where your QGIS is installed (should work on all platforms)
#if your QGIS is installed to /usr or /usr/local you can leave this next step out
export LIB_DIR=/home/timlinux/apps
cmake ..
make
./timtut3
Mac Specific Notes
After building the application bundle (cmake; make) you can copy the spatial
reference system database into the bundle to avoid 'cant find resource' type
errors:
mkdir -p qgis_example3.app/Contents/MacOS/share/qgis/resources/
cp -r /Applications/qgis.app/Contents/MacOS/share/qgis/resources/* \
qgis_example3.app/Contents/MacOS/share/qgis/resources/