メインページ/QGIS/coding-compilation guide/creating cpp applications/
提供: OSGeo.JP Wiki
2009年9月9日 (水) 03:22時点におけるArctic tern265 (トーク | 投稿記録)による版
\section{Creating C++ Applications} \section{C++アプリケーションの作成} 全ての人が完璧なデスクトップGISアプリケーションを求めているわけではありません。 時には、別の目的で作成されたアプリケーションの中に地図を表示するウィジェットを埋め込みたいだけ、ということもあるでしょう。 おそらく、地図表示を備えたデータベースフロントエンドなどでしょうか。 このセクションでは、Francis Bolduc氏の以前の成果に基づいて作成された、Tim Sutton氏による2つのシンプルなコードの例を取り上げます。 これらはその他の興味深いチュートリアルとともにQGIS subversionリポジトリにあります。 \filename{https://svn.osgeo.org/qgis/trunk/code\_examples/}からリポジトリ全体を調べてみてください。 \subsection{シンプルなマッピングウィジェットの作成}\label{subsec:simple_widget} このチュートリアルではシンプルなマッピングウィジェットを作成します。 ウィジェットには特段の機能はありません。単にshapeファイルを読み込んで、ランダムに色を割り振って表示するだけのものです。 しかしながら、QGISをマッピングコンポーネントを埋め込むために利用する、ということを理解するのには役に立つでしょう。 まずはアプリケーションに必要なインクルードファイルを追加しましょう: \begin{verbatim} // // 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> \end{verbatim} まず、QtのQApplicationの代わりにQgsApplicatinoを使います。これはライブラリパスの位置を検索するなどの機能を持つスタティックメソッドを利用するためです。 provider registryとはシングルトン(訳注:アプリケーション内で唯一のインスタンスを生成するクラス)で、 vecto data providerプラグインを記録します。このクラスはプラグインをロードするなどの作業を全て行ってくれます。 single symbol rendererは最も基本的なsymbologyクラスで、デフォルトではランダムに選択された色(指定することも可能)を用いて点、線、 ポリゴンを描画します。 全てのベクタレイヤーはこのクラスに関連付けられたsymbologyを持っていなければなりません。 map layer registryは利用する全てのレイヤーを記録します。 vector layerクラスはmaplayerクラスを継承しており、ベクタレイヤー固有の機能拡張がなされています。 最後に、mapcanvasはメインのマップ領域で、マップデータを表示する描画可能ウィジェットです。 それではアプリケーションの初期化に進みましょう。。。 \begin{verbatim} 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"; \end{verbatim} まず、qgsapplicationオブジェクトを作成し、いくつかの変数を定義しています。 このチュートリアルがもともとUbuntu Linux 8.10でテストしたものなので、 ベクタプロバイダプラグインの場所に開発用インストールディレクトリが指定されています。 一般的には、読者のシステムにおける標準的なライブラリパス(/usr/lib等)にQGISのライブラリ群を保存してあるほうが理にかなっているものと思われますが、 ここではとりあえずこうしておきます。 次の2つの変数定義(訳注:myLayerPathとmyLayerBaseName)では、これから読み込むShapeファイルを指定しています (ただし、独自のデータをここで代入する必要があるかもしれません)。 プロバイダ名は重要で、これはQGISにどのデータプロバイダを利用するかを指定します。 通常’ogr’もしくは’postgres’を指定します。 それでは実際にレイヤーオブジェクトを作成してみましょう。 \begin{verbatim} // Instantiate Provider Registry QgsProviderRegistry::instance(myPluginsDir); \end{verbatim} 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... \begin{verbatim} 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)); \end{verbatim} 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 we 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. \begin{verbatim} // 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(); \end{verbatim} 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. \begin{verbatim} // Start the Application Event Loop return app.exec(); } \end{verbatim} In the last step we simply start the Qt event loop and we are done. You can check out, compile and run this example using cmake like this: \begin{verbatim} 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 \end{verbatim} When we compile and run it here is what the running app looks like: \begin{figure}[ht] \begin{center} \caption{Simple C++ Application \osxcaption}\label{fig:cpp1_application}\smallskip \includegraphics[clip=true]{cpp1_application} \end{center} \end{figure} \subsection{Working with QgsMapCanvas} In the previous Section (Section~\ref{subsec:simple_widget}) we showed you how to use the QgsMapCanvas API to create a simple application that loads a shapefile and displays the points in it. But what good is a map that you can't interact with? In this second tutorial we will extend the previous tutorial by making it a QMainWindow application with a menu, toolbar and canvas area. We show you how to use QgsMapTool - the base class for all tools that are used to interact with the map canvas. The project will provide 4 toolbar icons for \begin{itemize} \item loading a map layer (layer name is hard coded in the application \item zooming in \item zooming out \item panning \end{itemize} 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. \textbf{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, we 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 we have included the headers for the QgsMapTools near the start of the file: \begin{verbatim} // // 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" \end{verbatim} 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: \begin{verbatim} //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())); \end{verbatim} Next we make a small toolbar to hold our toolbuttons. Note that the mpAction* actions were created in designer. \begin{verbatim} //create a little toolbar mpMapToolBar = addToolBar(tr("File")); mpMapToolBar->addAction(mpActionAddLayer); mpMapToolBar->addAction(mpActionZoomIn); mpMapToolBar->addAction(mpActionZoomOut); mpMapToolBar->addAction(mpActionPan); \end{verbatim} Now we create our three map tools: \begin{verbatim} //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); \end{verbatim} 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: \begin{verbatim} void MainWindow::panMode() { mpMapCanvas->setMapTool(mpPanTool); } \end{verbatim} \begin{figure}[ht] \begin{center} \caption{QMainWindow application with a menu, toolbar and canvas area \osxcaption}\label{fig:cpp2_application}\smallskip \includegraphics[clip=true, width=12cm]{cpp2_application} \end{center} \end{figure} \minisec{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: \begin{verbatim} svn co https://svn.osgeo.org/qgis/trunk/code_examples/2_basic_main_window cd 2_basic_main_window 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 ./timtut2 \end{verbatim}