QGIS API 3.0: レイヤ関係の変更点とその他もろもろ

QGIS 3.xでは2.xからレイヤ管理周りが大きく変更されています。
主なところを整理しつつ、凡例、オーバービューとの関連付けを調べてみましたが自分でもよくわからなくなってきました。

レイヤツリー

QGIS 3.xではQgsMapCanvasLayerクラスがQgsMapCanvasクラスが使用する内部クラスに変更され、表示/非表示の管理もしなくなりました。代わりにQgsLayerTreeLayerクラスが表示レイヤを管理しています。QgsLayerTreeLayerオブジェクトはQgsLayerTreeオブジェクトに登録して管理されますが、このオブジェクトはQGISのアプリケーションが生成されると1つ作成されます。

具体的には、まず以下のコードでプロジェクトにレイヤを追加します。

  QgsProject::instance()->addMapLayer( pLayer, true );

これを実行すると、途中イロイロあってQgsProjectが持っているメンバ変数mRootGroupinsertChildNodes()が呼ばれてレイヤが追加されます。

また、これとは別に、QgsMapCanvasオブジェクトにもレイヤリストを登録する必要があります。

  // centralwidgetはQgsMapCanvasオブジェクト
  // m_lstLayers は QList<QgsMapLayer *> 型オブジェクトで、
  // レイヤを読み込んだらこれに追加する
  m_lstLayers.append( pLayer );
  centralwidget->setLayers( m_lstLayers );

レイヤの表示/非表示

この状態でレイヤの表示/非表示を操作する場合は、一例としては以下のようにします。

  QgsLayerTreeLayer *p =
    QgsProject::instance()->layerTreeRoot()->findLayer( pLayer );
  p->setItemVisibilityChecked( false );

プラグインなどでは、これだけで大方事足ります。

アプリケーションを作成する場合

アプリケーションを作る場合はもう一つ手間がかかります。
まず、レイヤを管理しているクラスのメンバ変数にQgsLayerTreeMapCanvasBridgeクラスの変数を用意します。

  QgsLayerTreeMapCanvasBridge *mLayerTreeCanvasBridge;

次に、アプリケーションの初期化のところでキャンバスとレイヤツリーを関連付けます。

  // centralwidgetはQgsMapCanvasオブジェクト
  mLayerTreeCanvasBridge =
    new QgsLayerTreeMapCanvasBridge( QgsProject::instance()->layerTreeRoot(),
                                     centralwidget, this );
  connect( mLayerTreeCanvasBridge, &QgsLayerTreeMapCanvasBridge::canvasLayersChanged,
           centralwidget, &QgsMapCanvas::setLayers );

これをやっておかないと表示/非表示の操作ができません。
このクラスは、setCanvasLayers()関数でQgsLayerTreeLayer等のツリーに登録されるオブジェクトの表示/非表示のフラグを見てキャンバスに表示するレイヤを選別しています。

凡例との連携

凡例の操作でレイヤの表示/非表示を操作する、または逆にコードから表示/非表示を操作したときに凡例のチェックをOn/Offしたりするためには、レイヤツリーとの関連付けを行います。QGISの場合は凡例の専用クラスが用意されているのでそれを使います。

  // 凡例オブジェクトの作成
  mLayerTreeView = new QgsLayerTreeView( this );
  // QgsLayerTreeModelオブジェクトを作成
	QgsLayerTreeModel *model = new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), this );
  // 表示関連を操作可能にする
	model->setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility );
  // よくわからないが、ウィジェットを埋め込めるようになるとか
	model->setFlag( QgsLayerTreeModel::UseEmbeddedWidgets );
  // 凡例をツリーとして表示
	model->setFlag( QgsLayerTreeModel::ShowLegendAsTree );
  // チェックボックスを表示
	model->setFlag( QgsLayerTreeModel::AllowLegendChangeState );
  // 親ノードの操作を子ノードにも適用
	model->setFlag( QgsLayerTreeModel::ActionHierarchical );
  // 10以上のツリーは閉じた状態にする
	model->setAutoCollapseLegendNodes( 10 );

  // モデルをセット
	mLayerTreeView->setModel( model );

オーバービューとの連携

オーバービューを作成して連携させる場合は、上記のQgsLayerTreeMapCanvasBridgeクラスを使います。

クラス宣言
  // オーバービューキャンバス
  QgsMapOverviewCanvas *mOverviewCanvas;
  // なぜか用意されているQGISのドッキングウィジェット
  QgsDockWidget *mOverviewDock;
実装部
  mOverviewCanvas = new QgsMapOverviewCanvas( this, centralwidget );
  mOverviewDock = new QgsDockWidget( tr( "Overview" ), this );
  mOverviewDock->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );
  mOverviewDock->setWidget( mOverviewCanvas );
  addDockWidget( Qt::LeftDockWidgetArea, mOverviewDock );

  // QgsLayerTreeMapCanvasBridgeにセット
  mLayerTreeCanvasBridge->setOverviewCanvas( mOverviewCanvas );
アーカイブ