QGis二次开发 —— 4、对画布地图图层进行平移、缩放、自适应图层画面控制操作(附源码)

效果


在这里插入图片描述

功能说明

     本次开发的功能是基于上一版本 “QGis二次开发 —— 3、程序加载栅格tif与矢量shp文件可进行切换控制,可进行导出/导入工程(附源码)” 基础上继续制作的。

     本次软件增加了对画布地图图层进行平移、缩放、自适应图层画面控制操作。

源码

     main.cpp

#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>

#include <qgsapplication.h>

int main(int argc, char *argv[])
{
	// 参数三: 如果需要GUI应用程序,则设置为true;对于仅控制台应用程序,设置false
 	QgsApplication a(argc, argv, true);
 	QgsApplication::setPrefixPath("D:/Software/QGis-OSGeo4W/install/apps/qgis-ltr", true);		// 设置qgis路径
	QgsApplication::setPluginPath("D:/Software/QGis-OSGeo4W/install/apps/qgis-ltr/plugins");	// 设置插件路径
 	QgsApplication::initQgis();																	// 初始化QGis

	QtWidgetsApplication1 w;
	w.show();
	return a.exec();
}

     QtWidgetsApplication1.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"

#include <QtMath>

#include <qgsmapcanvas.h>
#include <qgsmaptoolpan.h>
#include <qgsmaptoolzoom.h>

class QtWidgetsApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication1(QWidget *parent = nullptr);
    ~QtWidgetsApplication1();

protected:
	// 将画布放在ui的Widget上,供显示
	void initQgsMapCanvas();

	// 加载本地.tif、.shp文件
	bool loadLocalFile(const QString &RasterFileName, const QString &VectorFileName);

	// 删除画布上所有图层并更新画布
	void removeMapLayers();

protected slots:
	// 切换显示画布上的矢量、栅格图层
	void sltQgsShowFile(int);

	/***************************** UI *****************************/
	// 通过按钮驱动进行加载本地文件
	void on_btn_qgsLoadFile_clicked();
	
	// 保存QGIS工程项目
	void on_btn_SaveQgisProject_clicked();

	// 导入QGIS工程项目
	void on_btn_LoadQgisProject_clicked();

	// 关闭QGIS工程项目
	void on_btn_CloseQgisProject_clicked();

	// 自适应完全画面
	void on_btn_entireScreen_clicked();

	// 平移画布地图
	void on_btn_move_clicked();

	// 平移缩小地图
	void on_btn_scaleMin_clicked();
	// 平移缩小地图
	void on_btn_scaleMax_clicked();
	/**************************************************************/

private:
    Ui::QtWidgetsApplication1Class ui;

	// 画布
	QgsMapCanvas *qMapCanvas = nullptr;

	// 图层列表: qMapLayerList为真实使用,qVirtualMapLayerList为虚拟使用。真实使用时会增删、虚拟使用则仅在函数内增加后则不再增删。
	QList<QgsMapLayer*> qMapLayerList, qVirtualMapLayerList;

	// 地图工具 - 鼠标平移地图工具 
	QgsMapToolPan *qMapToolPan = nullptr;
	// 地图工具 - 鼠标缩放地图工具 
	QgsMapToolZoom *qMapToolZoom_In = nullptr, *qMapToolZoom_Out = nullptr;
};

     QtWidgetsApplication1.cpp

#include "QtWidgetsApplication1.h"

#include <QMessageBox>
#include <QComboBox>
#include <QGridLayout>

#include <qgsrasterlayer.h>
#include <qgsvectorlayer.h>
#include <qgsproject.h>

const QString QGisProjectFileName = "qgs_project.qgs";

QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent) : QMainWindow(parent)
{
    ui.setupUi(this);

	initQgsMapCanvas();
}

QtWidgetsApplication1::~QtWidgetsApplication1()
{
	removeMapLayers();

	QLayout *GridLayout = ui.qgsMapCanvasWidget->layout();
	if (GridLayout) 
	{
		GridLayout->removeWidget(qMapCanvas);
		delete GridLayout; 
	}GridLayout = nullptr;

	if (qMapCanvas) 
	{
		qMapCanvas->unsetMapTool(qMapToolPan); 
		
		delete qMapCanvas; 
	}qMapCanvas = nullptr;
}

void QtWidgetsApplication1::initQgsMapCanvas()
{
	// 创建地图画布对象
	qMapCanvas = new QgsMapCanvas(this);
	QGridLayout *GridLayout = new QGridLayout;
	GridLayout->addWidget(qMapCanvas);
	ui.qgsMapCanvasWidget->setLayout(GridLayout);

	// 创建地图平移对象
	qMapToolPan = new QgsMapToolPan(qMapCanvas);

	// 创建地图缩放对象
	qMapToolZoom_In = new QgsMapToolZoom(qMapCanvas, true);
	qMapToolZoom_Out = new QgsMapToolZoom(qMapCanvas, false);
}

bool QtWidgetsApplication1::loadLocalFile(const QString &RasterFileName, const QString &VectorFileName)
{
	// 创建矢量图层对象并加入本地文件
	QgsVectorLayer *qVectorLayer = new QgsVectorLayer(VectorFileName, "shp");
	if (!qVectorLayer->isValid()) { return false; }
	qMapLayerList << qVectorLayer;
	qVirtualMapLayerList << qVectorLayer;
	ui.cb_qgsShowFile->addItem("shp", 0);	// 1为qVectorLayer所在qMapLayerList的序号

 	// 创建光栅图层对象加入本地文件
	QgsRasterLayer *qRasterLayer = new QgsRasterLayer(RasterFileName, "tif");
 	if (!qRasterLayer->isValid()) { return false; }
 	// 设置对比度增强(主要用于栅格图像;矢量图像不需要)。参数1算法:线性直方图、参数2界限范围:实际最小最大值
 	qRasterLayer->setContrastEnhancement(QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax);
	qMapLayerList << qRasterLayer;
	qVirtualMapLayerList << qRasterLayer;
 	ui.cb_qgsShowFile->addItem("tif",1);	// 0为qRasterLayer所在qMapLayerList的序号

	// 画布设置
	qMapCanvas->setLayers(qMapLayerList);							// 设置应在画布中显示的图层列表
	qMapCanvas->setDestinationCrs(qMapLayerList[0]->crs());			// 设置目标坐标参照系为输入光栅图层的坐标系
	qMapCanvas->setExtent(qMapLayerList[0]->extent());				// 设置画布范围为输入光栅图层的范围
	qMapCanvas->setCurrentLayer(qMapLayerList[0]);					// 设置画布当前图层为输入光栅图层
	qMapCanvas->refresh();											// 刷新画布

	// 将图层列表添加到已加载图层的映射中
	QgsProject::instance()->addMapLayers(qMapLayerList);

	return true;
}

void QtWidgetsApplication1::removeMapLayers()
{
	if (!qMapLayerList.isEmpty()) 
	{
		qMapLayerList.clear(); 
		qVirtualMapLayerList.clear();
	}

	qMapCanvas->setLayers(QList<QgsMapLayer*>());
	qMapCanvas->refresh();
}

void QtWidgetsApplication1::on_btn_qgsLoadFile_clicked()
{
	loadLocalFile("./world.tif", "./china.shp");


	ui.btn_SaveQgisProject->setEnabled(true);
	ui.btn_CloseQgisProject->setEnabled(true);
	ui.cb_qgsShowFile->setEnabled(true);
	ui.btn_qgsLoadFile->setEnabled(false);
	connect(ui.cb_qgsShowFile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtWidgetsApplication1::sltQgsShowFile);
	ui.btn_entireScreen->setEnabled(true);
	ui.btn_move->setEnabled(true);
	ui.btn_scaleMin->setEnabled(true);
	ui.btn_scaleMax->setEnabled(true);
}

void QtWidgetsApplication1::on_btn_SaveQgisProject_clicked()
{
	// 工程文件扩展名为: .qgz、.qgs
	QgsProject::instance()->setFileName(QGisProjectFileName);
	QgsProject::instance()->write();
}

void QtWidgetsApplication1::on_btn_LoadQgisProject_clicked()
{
	/*****************************************************************/
	int aaa = QgsProject::instance()->count();
	int aaa1 = qMapCanvas->layerCount();

	// 加载前先将之前的画布、画布上的图层清空
	removeMapLayers();
	
	int ccc = QgsProject::instance()->count();
	int ccc2 = qMapCanvas->layerCount();
	
	/* 重要: 以上测试说明当qMapLayerList删除,那么对应画布的layer与工程实例的mapLayer也会自动清空! */
	/*****************************************************************/

	if (!QgsProject::instance()->read(QGisProjectFileName))
	{
		QMessageBox::critical(this, "ERROR", "load QGIS Project fail!", QMessageBox::Yes);
		return;
	}
	qMapLayerList = qVirtualMapLayerList = QgsProject::instance()->mapLayers().values();
	qMapCanvas->setLayers(qMapLayerList);						// 设置画布当前图层为输入光栅图层
	qMapCanvas->setDestinationCrs(qMapLayerList[0]->crs());		// 设置目标坐标参照系为输入光栅图层的坐标系
	qMapCanvas->setExtent(qMapLayerList[0]->extent());			// 设置画布范围为输入光栅图层的范围
	qMapCanvas->setCurrentLayer(qMapLayerList[0]);				// 设置画布当前图层为输入光栅图层
	qMapCanvas->refresh();										// 刷新画布

	ui.cb_qgsShowFile->addItem("shp", 0);	// 1为qVectorLayer所在qMapLayerList的序号
	ui.cb_qgsShowFile->addItem("tif", 1);	// 0为qRasterLayer所在qMapLayerList的序号
	ui.cb_qgsShowFile->setEnabled(true);
	ui.btn_qgsLoadFile->setEnabled(false);
	connect(ui.cb_qgsShowFile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtWidgetsApplication1::sltQgsShowFile);
	ui.btn_entireScreen->setEnabled(true);
	ui.btn_move->setEnabled(true);
	ui.btn_scaleMin->setEnabled(true);
	ui.btn_scaleMax->setEnabled(true);
	ui.btn_CloseQgisProject->setEnabled(true);
	ui.btn_SaveQgisProject->setEnabled(true);
	
	qDebug() << "AA:" << QgsProject::instance()->count() << "  " << QgsProject::instance()->mapLayers().count() << " " << qMapCanvas->layerCount() << "    " << qMapLayerList.size() << " " << qVirtualMapLayerList.size();
}

void QtWidgetsApplication1::on_btn_CloseQgisProject_clicked()
{
	// 加载前先将之前的画布、画布上的图层清空
	removeMapLayers();

	ui.btn_CloseQgisProject->setEnabled(false);
	ui.btn_SaveQgisProject->setEnabled(false);
	ui.btn_entireScreen->setEnabled(false);
	ui.btn_move->setEnabled(false);
	ui.btn_scaleMin->setEnabled(false);
	ui.btn_scaleMax->setEnabled(false);
	disconnect(ui.cb_qgsShowFile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtWidgetsApplication1::sltQgsShowFile);
	ui.cb_qgsShowFile->setEnabled(false);
	ui.btn_LoadQgisProject->setEnabled(true);
	ui.btn_qgsLoadFile->setEnabled(true);
	ui.cb_qgsShowFile->clear();

	qDebug() << "BB:" << QgsProject::instance()->count() << "  " << QgsProject::instance()->mapLayers().count() << " " << qMapCanvas->layerCount() << "    " << qMapLayerList.size() << " " << qVirtualMapLayerList.size();
	
	qMapCanvas->unsetMapTool(qMapCanvas->mapTool());
	QgsProject::instance()->clear(); 

	qDebug() << "CC:" << QgsProject::instance()->count() << "  " << QgsProject::instance()->mapLayers().count() << " " << qMapCanvas->layerCount() << "    " << qMapLayerList.size() << " " << qVirtualMapLayerList.size();
}

void QtWidgetsApplication1::on_btn_entireScreen_clicked()
{
	if (qMapCanvas) 
	{
		// 卸载画布地图工具
		qMapCanvas->unsetMapTool(qMapCanvas->mapTool());

		// 缩放到所有层的全部范围
		qMapCanvas->zoomToFullExtent();
	}
}

void QtWidgetsApplication1::on_btn_move_clicked()
{
	// 画布加入地图平移工具
	qMapCanvas->setMapTool(qMapToolPan);
}

void QtWidgetsApplication1::on_btn_scaleMin_clicked()
{
	// 画布加入地图缩小工具
	qMapCanvas->setMapTool(qMapToolZoom_In);
}

void QtWidgetsApplication1::on_btn_scaleMax_clicked()
{
	// 画布加入地图放大工具
	qMapCanvas->setMapTool(qMapToolZoom_Out);
}

void QtWidgetsApplication1::sltQgsShowFile(int index)
{
	/* 重要: 以下操作说明qMapLayerList变化,那么对应画布的layer与工程实例的mapLayer也会自动变化! */
	if (qVirtualMapLayerList.size() > index)
	{
		qMapLayerList.clear();
		qMapLayerList << qVirtualMapLayerList[index];

		qMapCanvas->setLayers(qMapLayerList);						// 设置画布当前图层为输入光栅图层
   		qMapCanvas->setDestinationCrs(qMapLayerList[0]->crs());		// 设置目标坐标参照系为输入光栅图层的坐标系
   		qMapCanvas->setExtent(qMapLayerList[0]->extent());			// 设置画布范围为输入光栅图层的范围
   		qMapCanvas->refresh();										// 刷新画布
	}
}

     QtWidgetsApplication1.ui

在这里插入图片描述

关注

笔者 - jxd

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信必诺

嗨,支持下哥们呗。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值