Você está na página 1de 11

QGIS Planet

Build and deploy c++ QGIS app on


windows
February 27, 2014 QGIS Tips
After a lot of troubles, I managed to compile and deploy a QGIS c++ app on windows. This small guide will describe the steps I
followed. This has been tested on win xp and windows 7, both in 32 bits.
Development environment
Your app must be built using MSVC 9.0 (2008) since QGIS in OSGeos package was built with it. Hence, MinGW cannot be used.
1. Install Microsoft Visual Studio Express 2008.
2. Install QGIS and Qt libs using OSGeo4W installer
3. Install Qt Creator
4. If you want a debugger,you should install CDB. This can be achieved by installing Windows SDK environment. In the
installation process, only select Debugging toos for windows.
I wasnt able to use the compiler yet, so I am not 100% sure about 4.
Now, if you want to build using Qt Creator, it must be started in a proper environment. Adapt this batch to launch Qt Creator:
ECHO Setting up QGIS DEV ENV

set PYTHONPATH=

set OSGEO4W_ROOT=C:\OSGeo4W
call "%OSGEO4W_ROOT%\bin\o4w_env.bat"

@set QMAKESPEC=win32-msvc2008
@set PATH=%OSGEO4W_ROOT%\bin;%OSGEO4W_ROOT%\apps\qgis-dev\bin;%PATH%

@set INCLUDE=%INCLUDE%;%OSGEO4W_ROOT%\include;%OSGEO4W_ROOT%\apps\qgis-de
v\include
@set LIB=%LIB%;%OSGEO4W_ROOT%\lib;%OSGEO4W_ROOT%\apps\qgis-dev\lib

path %OSGEO4W_ROOT%\bin;%SYSTEMROOT%\System32;%SYSTEMROOT%;%SYSTEMROOT%\S
ystem32\wbem;C:\Progra~1\Git\bin;C:\Qt\qtcreator-3.0.1\bin;%PATH%

set VS90COMNTOOLS=C:\Program Files\Microsoft Visual Studio 9.0\Common7\To
ols\
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86

start "Qt Creator" /B C:\Qt\qtcreator-3.0.1\bin\qtcreator.exe %*
Then, you need to configure a proper kit in Qt Creator.
1. Go to Options -> Build & Run -> Compilers and check that Microsoft Visual C++ Compiler 9.0 is correctly detected.
2. Then in Qt Versions tab, add Qt from the OSGeO installation, normally c:\OSGeo4W\bin\qmake.exe
3. In Debuggers tab, add cdb.exe found in c:\Debugging tools for windows\
4. Finally, check in Kits that it is properly configured.
Building the application
This is what looks like an application project file.
QT += core gui xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = hfp
TEMPLATE = app
SOURCES += YOURSOURCES
HEADERS +=YOUR HEADERS
FORMS += YOUR FORMS
RESOURCES += images/images.qrc

win32:CONFIG(Release, Debug|Release) {
LIBS += -L"C:/OSGeo4W/lib/" -lQtCore4
LIBS += -L"C:/OSGeo4W/lib/" -lQtGui4
LIBS += -L"C:/OSGeo4W/lib/" -lQtXml4
LIBS += -L"C:/OSGeo4W/apps/qgis-dev/lib/" -lqgis_core
LIBS += -L"C:/OSGeo4W/apps/qgis-dev/lib/" -lqgis_gui
}
else:win32:CONFIG(Debug, Debug|Release) {
PRE_TARGETDEPS += C:/OSGeo4W/lib/QtCored4.lib
PRE_TARGETDEPS += C:/OSGeo4W/lib/QtGuid4.lib
PRE_TARGETDEPS += C:/OSGeo4W/lib/QtXmld4.lib
LIBS += -L"C:/OSGeo4W/lib/" -lQtCored4
LIBS += -L"C:/OSGeo4W/lib/" -lQtGuid4
LIBS += -L"C:/OSGeo4W/lib/" -lQtXmld4
LIBS += -L"C:/OSGeo4W/apps/qgis-dev/lib/" -lqgis_core
LIBS += -L"C:/OSGeo4W/apps/qgis-dev/lib/" -lqgis_gui
}
win32:{
INCLUDEPATH += C:/OSGeo4W/include
DEPENDPATH += C:/OSGeo4W/include
INCLUDEPATH += C:/OSGeo4W/apps/qgis-dev/include
DEPENDPATH += C:/OSGeo4W/apps/qgis-dev/include
DEFINES += GUI_EXPORT=__declspec(dllimport) CORE_EXPORT=__declspec(dllim
port)
}
unix {
LIBS += -L/usr/local/lib/ -lqgis_core -lqgis_gui
LIBS += -L/usr/local/lib/qgis/plugins/ -lgdalprovider
INCLUDEPATH += /usr/local/include/qgis
DEFINES += GUI_EXPORT= CORE_EXPORT=
}
Remarks
GUI_EXPORT and CORE_EXPORT must be set to __declspec(dllimport). I dont know exactly what it means, but I
found out reading this thread, with some hazardous tries. If you dont set these, you wont be able to call any variable defined
as extern in QGIS (e.g. cursors).
Qt release libraries shall not be mixed up with debug config in your project. In other words, use release libs for release mode
and debug libs for debug mode.
With this, you should be able to compile your QGIS application in Qt Creator!
You can find some coding examples on github which are a bit old but still useful to start.
Now, to get the whole potential of QGIS libs, you must initialize the QgsApplication in your main window class:
#if defined(Q_WS_WIN)
QString pluginPath = "c:\\OSGeo4W\\apps\\qgis-dev\\plugins";
QString prefixPath = "c:\\OSGeo4W\\apps\\qgis-dev\\";
#else
QString pluginPath = "/usr/local/lib/qgis/plugins/";
QString prefixPath = "/usr/local";
#endif

QgsApplication::setPluginPath( pluginPath );
QgsApplication::setPrefixPath( prefixPath, true);
QgsApplication::initQgis();
Deploying on windows
Since QGIS is not to be installed on the target computer, the built app will not be able to find the path declared in previous code.
There is probably a better approach, but here is a way to solve this:
Change the path to
QString pluginPath = "c:\\myapp\\qgis\plugins";
QString prefixPath = "c:\\myapp\\qgis";
This means you must deploy the app to this exact location: c:\myapp. In this directory, you need to create a qgis folder in which you
will copy c:\OSGeo4W\apps\qgis-dev\resources and c:\OSGeo4W\apps\qgis-dev\plugins.
Besides, this you will need to copy some DLLs to be able to run the applications. You might want to use the dependency walker to
find which are needed.
The batch file hereafter creates a folder on the building machine that will contain all the needed files in my case (it might be different
in your case).
rmdir c:\myapp /Q /S
mkdir c:\myapp
mkdir c:\myapp\iconengines
mkdir c:\myapp\qgis
mkdir c:\myapp\qgis\resources
mkdir c:\myapp\qgis\plugins

copy PATHTOMYAPP\build-myapp-Desktop-Release\release\myapp.exe c:\myapp\
copy c:\OSGeo4W\bin\QtCore4.dll c:\myapp\
copy c:\OSGeo4W\bin\QtGui4.dll c:\myapp\
copy c:\OSGeo4W\bin\QtXml4.dll c:\myapp\
copy c:\OSGeo4W\bin\QtNetwork4.dll c:\myapp\
copy c:\OSGeo4W\bin\QtSvg4.dll c:\myapp\
copy c:\OSGeo4W\bin\QtWebKit4.dll c:\myapp\

copy c:\OSGeo4W\bin\zlib_osgeo.dll c:\myapp\
copy c:\OSGeo4W\bin\msvcr71.dll c:\myapp\
copy c:\OSGeo4W\bin\phonon4.dll c:\myapp\
copy c:\OSGeo4W\bin\proj.dll c:\myapp\
copy c:\OSGeo4W\bin\geos_c.dll c:\myapp\
copy c:\OSGeo4W\bin\gdal110.dll c:\myapp\
copy c:\OSGeo4W\bin\ogdi_32b1.dll c:\myapp\
copy c:\OSGeo4W\bin\libexpat.dll c:\myapp\
copy c:\OSGeo4W\bin\xerces-c_3_1.dll c:\myapp\
copy c:\OSGeo4W\bin\LIBPQ.dll c:\myapp\
copy c:\OSGeo4W\bin\SSLEAY32.dll c:\myapp\
copy c:\OSGeo4W\bin\LIBEAY32.dll c:\myapp\
copy c:\OSGeo4W\bin\krb5_32.dll c:\myapp\
copy c:\OSGeo4W\bin\comerr32.dll c:\myapp\
copy c:\OSGeo4W\bin\k5sprt32.dll c:\myapp\
copy c:\OSGeo4W\bin\gssapi32.dll c:\myapp\
copy c:\OSGeo4W\bin\hdf_fw.dll c:\myapp\
copy c:\OSGeo4W\bin\mfhdf_fw.dll c:\myapp\
copy c:\OSGeo4W\bin\jpeg_osgeo.dll c:\myapp\
copy c:\OSGeo4W\bin\jpeg12_osgeo.dll c:\myapp\
copy c:\OSGeo4W\bin\netcdf.dll c:\myapp\
copy c:\OSGeo4W\bin\geotiff.dll c:\myapp\
copy c:\OSGeo4W\bin\libtiff.dll c:\myapp\
copy c:\OSGeo4W\bin\sqlite3.dll c:\myapp\
copy c:\OSGeo4W\bin\spatialite4.dll c:\myapp\
copy c:\OSGeo4W\bin\freexl.dll c:\myapp\
copy c:\OSGeo4W\bin\iconv.dll c:\myapp\
copy c:\OSGeo4W\bin\libxml2.dll c:\myapp\
copy c:\OSGeo4W\bin\LIBMYSQL.dll c:\myapp\
copy c:\OSGeo4W\bin\hdf5.dll c:\myapp\
copy c:\OSGeo4W\bin\szip.dll c:\myapp\
copy c:\OSGeo4W\bin\libcurl.dll c:\myapp\
copy c:\OSGeo4W\bin\zlib1.dll c:\myapp\
copy c:\OSGeo4W\bin\openjp2.dll c:\myapp\
copy c:\OSGeo4W\bin\spatialindex1.dll c:\myapp\
copy c:\OSGeo4W\bin\qwt5.dll c:\myapp\

copy c:\OSGeo4W\apps\qt4\plugins\iconengines\qsvgicon4.dll c:\myapp\icone
ngines\

copy C:\Progra~1\Git\bin\libiconv-2.dll c:\myapp\
copy C:\Progra~1\Git\bin\libintl-8.dll c:\myapp\

copy c:\OSGeo4W\apps\qgis-dev\bin\qgis_Core.dll c:\myapp\
copy c:\OSGeo4W\apps\qgis-dev\bin\qgis_gui.dll c:\myapp\
copy c:\OSGeo4W\apps\qgis-dev\bin\msvcp90.dll c:\myapp\

copy c:\windows\system32\msvcp100.dll c:\myapp\
copy c:\windows\system32\msvcr100.dll c:\myapp\

copy C:\OSGeo4W\apps\qgis-dev\resources\* c:\myapp\qgis\resources
copy C:\OSGeo4W\apps\qgis-dev\plugins\* c:\myapp\qgis\plugins
To be able to run the app, on a fresh windows XP, I had to install:
Microsoft Visual C++ 2008 Redistributable Package (x86)
Microsoft Visual C++ 2005 Redistributable Package (x86)
Microsoft Visual C++ 2005 Service Pack 1 Redistributable Package MFC Security Update
And copy the whole folder c:\myapp from the building machine to the target machine.
It seems that from Vista, the 2005 redistributable package is included. So, no need to install it.
And voil!


by 3nids at 9:32 AM under c++ , compile , cpp , deploy , qgis , windows (Comments)
Hepler modules for development of
QGIS plugins
May 16, 2013 QGIS Tips
There are two things I have coded, re-coded and re-re-coded through all my plugins: the management of the settings and the
management of combo boxes associated to layers and their fields.
I have decided to write two generic python modules to solve these tasks to avoid reinventing the wheel every time.
The first one is called QGIS setting manager.
This module allows you to:
manage different types of settings (bool, string, color, integer, double, stringlist)
read and write settings in QGIS application or in the QGIS project
automatically set widgets from corresponding setting
automatically write settings from widgets of a dialog
This means that the class of a dialog dedicated to editing the plugins settings can be reduced to just a few lines.
You just have to name widgets according to settings and the module automatically detect the widgets, sets/reads the value from the
widget and read/write the settings accordingly.
A setting class would look like this
from qgissettingmanager import *

class MySettings(SettingManager):
def __init__(self):
SettingManager.__init__(self, myPluginName)
self.addSetting("myVariable", "bool", "global", True)
reading and write settings are performed by doing
self.settings = MySettings()
self.settings.setValue("myVariable", False)
myVariable = self.settings.value("myVariable")
and a dialog looks like this
class MyDialog(QDialog, Ui_myDialog, SettingDialog):
def __init__(self):
QDialog.__init__(self)
self.setupUi(self)
self.settings = MySettings()
SettingDialog.__init__(self, self.settings)
You can find a complete howto here and look at the code on github.
The second module is called QGIS combo manager. This module autmatically manages combo box widgets for layers, fields of
vector layers and bands of raster layers.
You can associate a field combo to a layer combo: as soon as the layer has been modified, the fields are updated to the current
layer.
Associating a combo box to layers and another one to its fields would look like this:
from qgiscombomanager import *

self.layerComboManager = VectorLayerCombo(self.layerComboWidget)
self.myFieldComboManager = FieldCombo(self.myFieldComboManager, self.laye
rComboManager)
You can find a complete howto here and look at the code on github.


by 3nids at 1:55 PM under plugins , setting (Comments)
Identify feature on map
February 14, 2013 QGIS Tips
A very awaited feature is now available in the master version of QGIS: identifying features in the map!
You can define the class of the map tool as follows:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *

class IdentifyGeometry(QgsMapToolIdentify):
def __init__(self, canvas):
self.canvas = canvas
QgsMapToolIdentify.__init__(self, canvas)

def canvasReleaseEvent(self, mouseEvent):
results = self.identify(mouseEvent.x(),mouseEvent.y(), self.TopDownStop
AtFirst, self.VectorLayer)
if len(results) > 0:
self.emit( SIGNAL( "geomIdentified" ), results[0].mLayer, results[0].m
Feature)
This class will try to identify a feature of any visible vector layer and returning the first found feature (using layer order). Then, it will
emit the signal with the layer and the feature identified.
To customize this, you can use the identify method with different arguments:
type of layer
type of identification (current layer, top-down, top-down stop at first or the QGIS setting)
list of layers
There is two ways of calling the identify methods:
identify (x, y, layerList=[], IdentifyMode mode=self.DefaultQgsSetting)
identify (x, y, identifyMode, layerType=AllLayers)
Identify mode and layer types are defined here. Mainly the options can be:
Identify mode: self.DefaultQgsSetting, self.ActiveLayer, self.TopDownStopAtFirst, self.TopDownAll
Layer type: self.AllLayers, self.VectorLayer, self.RasterLayer
Both methods return a structure IdentifyResult defined in the API. Mainly, it contains:
the feature (mFeature) if the identified layer is a vector layer
the corresponding layer (mLayer)
the derived attributes (mDerivedAttributes): the raster value for raster layers
In your plugin main code, you can define a toolbox button to enable your map tool:
class myPlugin():
def initGui(self):
self.mapToolAction = QAction(QIcon(":/plugins/myPlugin/icons/myIcon.png
"), "My Plugin", self.iface.mainWindow())
self.mapToolAction.setCheckable(True)
QObject.connect(self.mapToolAction, SIGNAL("triggered()"), self.mapTool
Init)
self.iface.addToolBarIcon(self.mapToolAction)
self.iface.addPluginToMenu("&My Plugin", self.mapToolAction)

def mapToolInit(self):
canvas = self.iface.mapCanvas()
if self.mapToolAction.isChecked() is False:
canvas.unsetMapTool(self.mapTool)
return
self.mapToolAction.setChecked( True )
self.mapTool = IdentifyGeometry(canvas)
QObject.connect(self.mapTool , SIGNAL("geomIdentified") , self.doSometi
ng )
canvas.setMapTool(self.mapTool)
QObject.connect( canvas, SIGNAL( "mapToolSet(QgsMapTool *)" ), self.map
ToolChanged)</em>

def doSomething(self, layer, feature):
# do something
If you want your plugin to be back compatible with version before 1.9, you can select the features at the clicked point using a given
tolerance and using the current layer:
try:
from qgis.gui import QgsMapToolIdentify
except:
from qgis.gui import QgsMapTool as QgsMapToolIdentify

class IdentifyGeometry(QgsMapToolIdentify):
def __init__(self, canvas):
self.canvas = canvas
QgsMapToolIdentify.__init__(self, canvas)

def canvasReleaseEvent(self, mouseEvent):
try:
results = self.identify(mouseEvent.x(),mouseEvent.y(), self.TopDownStop
AtFirst, self.VectorLayer)
if len(results) > 0:
self.emit( SIGNAL( "geomIdentified" ), results[0].mLayer, results[0].m
Feature)
except: # qgis <1.9
point = self.toMapCoordinates( mouseEvent.pos() )
layer = self.canvas.currentLayer()
if layer == None:
return
if layer.type() != QgsMapLayer.VectorLayer:
return
point = self.canvas.mapRenderer().mapToLayerCoordinates(layer, point)
pixTolerance = 6
mapTolerance = pixTolerance * self.canvas.mapUnitsPerPixel()
rect = QgsRectangle(point.x()-mapTolerance,point.y()-mapTolerance,poin
t.x()+mapTolerance,point.y()+mapTolerance)
provider = layer.dataProvider()
provider.select([], rect, True, True)
subset = []
f = QgsFeature()
while (provider.nextFeature(f)):
subset.append(f)
if len(subset) == 0:
return
if len(subset) > 1:
idx = QgsSpatialIndex()
for f in subset:
idx.insertFeature(f)
nearest = idx.nearestNeighbor( point, 1 )
layer.featureAtId(nearest[0],f, True, False)
self.emit( SIGNAL( "geomIdentified" ), layer, f)
Note, that this last code (for version <1.9) does not consider scale dependent visibility and can therefore return a feature which is not
visible in the map!


by 3nids at 10:48 AM under map tools , plugins (Comments)
Page 1 of 1 ( 3 posts )

Back to Top

Você também pode gostar