本篇文章将在之前讲的以下两篇文章的基础上,实现添加矢量图层、栅格图层及图层列表的功能,代码均参考QGIS源码实现。
QGIS二次开发1: vs工程环境配置_guoqiong07的博客-CSDN博客
QT界面开发1:使用QtitanRibbon5开发软件界面_guoqiong07的博客-CSDN博客
最终要实现的效果如下:
1.中间画布展示矢量、栅格数据;
2.左侧展示图层列表,当勾选/取消勾选图层时,中间画布随之展示/隐藏。
接着上一篇讲解QT界面开发的文章中第6点【添加侧边栏】,现在我们讲解如何在侧边栏中添加图层列表。
QT界面开发1:使用QtitanRibbon5开发软件界面_guoqiong07的博客-CSDN博客
实现图层列表的代码如下:
//新建图层树形控件
mLayerTreeView = new QgsLayerTreeView(this);
mLayerTreeView->setObjectName(QStringLiteral("theLayerTreeView"));
//创建QgsLayerTreeModel 实例,并允许用户通过点选复选框手动隐藏/显示图层
QgsLayerTreeModel* model = new QgsLayerTreeModel(QgsProject::instance()->layerTreeRoot(), this);
model->setFlag(QgsLayerTreeModel::AllowNodeChangeVisibility);
model->setAutoCollapseLegendNodes(10);
//将View视图与Model数据绑定
mLayerTreeView->setModel(model);
//将工程实例中的图层根节点与画布绑定,实现与地图画布控件的数据交互
mLayerTreeCanvasBridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), mMapCanvas, this);
//将View添加到左侧的Dock控件中展示
mLayerMapDock->setWidget(mLayerTreeView);
也就是我们这里所说的图层列表。QGIS中专门提供了QgsLayerTreeView
类来实现图层列表功能,而这里的图层列表实际上应该称之为图层树形控件,因为图层可以分组,每个分组下面可以有多个图层。
mLayerTreeView = new QgsLayerTreeView(this);
这里的Model实例,是通过调用QgsProject的实例中的layerTreeRoot()
方法来实现的,目的是为了获取当前工程的图层根节点。QgsProject封装了当前QGIS工程信息,一个应用程序只有一个QgsProject工程实例。
QgsLayerTreeModel* model = new QgsLayerTreeModel(QgsProject::instance()->layerTreeRoot(), this);
model->setFlag(QgsLayerTreeModel::AllowNodeChangeVisibility);
Model/View 架构实现了数据与视图的双向绑定,任何一方的变化都会反馈到另外一方。
mLayerTreeView->setModel(model);
QgsLayerTreeMapCanvasBridge是QGIS中图层管理的重要类,实现了当前工程中的图层与地图画布控件的数据交互。也就是当我们将图层添加到当前工程中时,地图画布mMapCanvas会渲染该图层进行显示。
mLayerTreeCanvasBridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), mMapCanvas, this);
图层列表的创建工作和绑定工作做完后,需要将该图层列表放在软件界面的某个地方进行展示,该代码段则是将mLayerTreeView放在之前创建好的mLayerMapDock控件中展示。
mLayerMapDock->setWidget(mLayerTreeView);
总结:图层列表、当前工程中的图层 、地图画布这是三个不同的概念,当我们将这三者绑定在一起后,才能正常实现添加图层到工程并进行展示。
在这篇文章中第2点【创建QAction】我们创建了添加栅格的槽函数slot_addRaterLayer。接下来实现该函数。
QT界面开发1:使用QtitanRibbon5开发软件界面_guoqiong07的博客-CSDN博客
#include
#include "qgsguiutils.h"
#include "QgsRasterLayer.h"
#include "QgsProject.h"
#include "QgsProviderRegistry.h"
#include "QgsMapCanvas.h"
#include "QgsVectorLayer.h"
具体的代码如下,内容比较简单,容易理解。
QStringList layerFiles;
QString e;
QString title = tr("Open Raster Layer");
QString rasterFileFilter = "All supported(*.tif *.img *.hgt *.grd);;GeoTIFF(*.tif *.tiff *.TIF *.TIFF);;Erdas Imagine Images(*.img *.IMG);;NetCDF(*.grd *.GRD);;STRMHGT File(*.hgt *.HGT)";
QgsGuiUtils::openFilesRememberingFilter(QStringLiteral("lastRasterFileFilter"), rasterFileFilter, layerFiles, e, title);
if (layerFiles.isEmpty())
return false;
// this is messy since some files in the list may be rasters and others may
// be ogr layers. We'll set returnValue to false if one or more layers fail
// to load.
bool returnValue = true;
QList myList;
for (auto myIterator = layerFiles.begin();
myIterator != layerFiles.end();
++myIterator)
{
QString errMsg;
bool ok = false;
if (QgsRasterLayer::isValidRasterFileName(*myIterator, errMsg))
{
QFileInfo myFileInfo(*myIterator);
QString layerName = myFileInfo.completeBaseName();
const QVariantMap uriDetails = QgsProviderRegistry::instance()->decodeUri(QStringLiteral("gdal"), *myIterator);
if (!uriDetails[QStringLiteral("layerName")].toString().isEmpty())
{
layerName = uriDetails[QStringLiteral("layerName")].toString();
}
// try to create the layer
QgsRasterLayer* layer = new QgsRasterLayer(*myIterator, layerName, QStringLiteral("gdal"));
if (layer && layer->isValid())
{
myList << layer;
ok = true;
}
} // valid raster filename
else
{
ok = false;
QString msg = tr("%1 is not a supported raster data source").arg(*myIterator);
if (!errMsg.isEmpty())
msg += '\n' + errMsg;
QMessageBox::warning(this, "Unsupported Data Source", msg);
}
if (!ok)
{
returnValue = false;
}
}
QgsProject::instance()->addMapLayers(myList);
return returnValue;
需要说明的是,rasterFileFilter 设置了支持打开的栅格影像格式;在最后,将创建好的栅格图层添加到工程中。由于之前做了图层列表、当前工程中的图层 、地图画布的绑定,添加的图层将会在图层列表中罗列出来,同时会在画布中展示当前图层。
QgsProject::instance()->addMapLayers(myList);
设置允许添加的矢量格式vectorFileFilter ,将创建好的图层添加到工程。
QStringList layerFiles;
QString e;
QString title = tr("Open Vector Layer");
QString vectorFileFilter = "OGR Layer(*.shp *.geojson *.gmt);; KML(*.kml)";
QgsGuiUtils::openFilesRememberingFilter(QStringLiteral("lastRasterFileFilter"), vectorFileFilter, layerFiles, e, title);
if (layerFiles.isEmpty())
return false;
QList layersToAdd;
for (QString src : layerFiles)
{
src = src.trimmed();
QFileInfo fi(src);
QString baseName = fi.completeBaseName();
// create the layer
QgsVectorLayer::LayerOptions options{ QgsProject::instance()->transformContext() };
options.loadDefaultStyle = false;
QgsVectorLayer* layer = new QgsVectorLayer(src, baseName, QStringLiteral("ogr"), options);
if (layer != nullptr && layer->isValid())
{
layersToAdd << layer;
}
else
{
delete layer;
QString msg = tr("%1 is not a valid or recognized data source.").arg(src);
QMessageBox::warning(this, tr("Invalid Data Source"), msg);
}
}
if (layersToAdd.size() > 0)
{
QgsProject::instance()->addMapLayers(layersToAdd);
}
return true;