メインページ/QGIS/coding-compilation guide/creating cpp applications/

提供: OSGeo.JP Wiki
移動: 案内検索
\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}
 
まずprovider registryを初期化しています。
シングルトンクラスなので静的なインスタンスの呼び出しを使用しており、引数にプロバイダライブラリ群へのパスを渡しています。
初期化されると、このパスからプロバイダライブラリ群をスキャンします。
 
続いてレイヤーを作成します。
 
\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}
 
このコードは極めて自明的です。以前に定義した変数を用いてレイヤーを作成したら、レイヤーにレンダラを割り付けます。
レンダラを作成する場合はジオメトリの種別を定義する必要がありますが、これはベクタレイヤーにジオメトリタイプを問い合わせることで行います。
次に、レイヤーをレイヤーセットと(これはどのレイヤーを描画するかや、レイヤーの順番をQgsMapCanvasが追跡するのに使用されます)
マップレイヤーレジストリに追加します。
最後に、レイヤーが表示されていることを確認します。
 
それでは、レイヤーを描画するマップキャンバスを作成しましょう。
 
\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}
 
ここでも特に手の込んだことはありません。
まず、キャンバスを作成し、キャンバスの範囲にレイヤーの範囲を割り当てています。
次に、ベクタレイヤーの描画にアンチエイリアスを使用するように設定します。
さらに、背景色の設定、キャンバスの凍結の解除、キャンバスを表示するようにした後、キャンバスを更新します。
 
\begin{verbatim}
  // Start the Application Event Loop
  return app.exec();
}
 
\end{verbatim}
 
最後のステップは、単にQtのイベントループを開始して終了です。
確認後、以下のようにcmakeを使ってこのコードをコンパイルし、実行することができます:
 
\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}
 
コンパイルして実行すると以下のように表示されます。
 
\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}