QGIS二次开发2:添加矢量、栅格图层及图层列表的实现

本篇文章将在之前讲的以下两篇文章的基础上,实现添加矢量图层、栅格图层及图层列表的功能,代码均参考QGIS源码实现。

QGIS二次开发1: vs工程环境配置_guoqiong07的博客-CSDN博客

QT界面开发1:使用QtitanRibbon5开发软件界面_guoqiong07的博客-CSDN博客

最终要实现的效果如下:

1.中间画布展示矢量、栅格数据;

2.左侧展示图层列表,当勾选/取消勾选图层时,中间画布随之展示/隐藏。

 QGIS二次开发2:添加矢量、栅格图层及图层列表的实现_第1张图片

一、图层列表的实现

 接着上一篇讲解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);

1.首先,创建一个图层树形控件。

也就是我们这里所说的图层列表。QGIS中专门提供了QgsLayerTreeView 类来实现图层列表功能,而这里的图层列表实际上应该称之为图层树形控件,因为图层可以分组,每个分组下面可以有多个图层。

mLayerTreeView = new QgsLayerTreeView(this);

2.接下来,创建Model实例。

这里的Model实例,是通过调用QgsProject的实例中的layerTreeRoot() 方法来实现的,目的是为了获取当前工程的图层根节点。QgsProject封装了当前QGIS工程信息,一个应用程序只有一个QgsProject工程实例。

	QgsLayerTreeModel* model = new QgsLayerTreeModel(QgsProject::instance()->layerTreeRoot(), this);
	model->setFlag(QgsLayerTreeModel::AllowNodeChangeVisibility);

3.接下来,绑定视图与数据。

 Model/View 架构实现了数据与视图的双向绑定,任何一方的变化都会反馈到另外一方。

mLayerTreeView->setModel(model);

4.接下来, 创建QgsLayerTreeMapCanvasBridge实例。

QgsLayerTreeMapCanvasBridge是QGIS中图层管理的重要类,实现了当前工程中的图层与地图画布控件的数据交互。也就是当我们将图层添加到当前工程中时,地图画布mMapCanvas会渲染该图层进行显示。


	mLayerTreeCanvasBridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), mMapCanvas, this);

5.将图层列表展示在左侧栏。

图层列表的创建工作和绑定工作做完后,需要将该图层列表放在软件界面的某个地方进行展示,该代码段则是将mLayerTreeView放在之前创建好的mLayerMapDock控件中展示。

	mLayerMapDock->setWidget(mLayerTreeView);

总结:图层列表、当前工程中的图层 、地图画布这是三个不同的概念,当我们将这三者绑定在一起后,才能正常实现添加图层到工程并进行展示。

二、添加栅格图层

在这篇文章中第2点【创建QAction】我们创建了添加栅格的槽函数slot_addRaterLayer。接下来实现该函数。

QT界面开发1:使用QtitanRibbon5开发软件界面_guoqiong07的博客-CSDN博客

1.添加引用的头文件。

#include 

#include "qgsguiutils.h"
#include "QgsRasterLayer.h"
#include "QgsProject.h"
#include "QgsProviderRegistry.h"
#include "QgsMapCanvas.h"
#include "QgsVectorLayer.h"

2.实现slot_addRaterLayer。

具体的代码如下,内容比较简单,容易理解。

    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;

你可能感兴趣的:(QGIS,c++,qt5)