QGIS二次开发(矢量数据编辑)

基于QGIS进行二次开发的正确姿势 最近一直在琢磨QGIS的二次开发,也踩过不少坑,好在最后的结果是好的。这里介绍一下我最喜欢的二次开发姿势。 阅读详情
AI摘要

该博客围绕GIS矢量数据编辑实习展开。介绍了任务要求,包括显示遥感影像、图层数据等。阐述了实现技术,涉及QgsVectorLayer和QgsRasterLayer类。详细说明了实现过程,如添加控件、定义函数等。最后展示了系统功能及关键代码,可实现工程打开、数据添加等操作。

实习四 GIS矢量数据编辑

4.1 任务要求

  1. 利用 QgsRasterLayer 和 QgsMapCavans 显示 GeoTiff 格式的遥感影像或 DEM 数据。
  2. 利用 QgsVectorLayer 和 QgsMapCavas 显示 shp 格式的图层数据和 qgs 格式的工程数据。
  3. 在显示矢量图时,查看、编辑矢量图的属性结构、属性值。
  4. 在显示矢量图时,查看、编辑矢量图的点、线、面的几何数据,
  5. 在显示矢量图时,编辑矢量图的图形参数。

4.2 完成过程

4.2.1 GIS矢量数据编辑实现技术

在QGIS中,GIS矢量数据编辑等功能的实现主要应用到了<QgsVectorLayer>类和<QgsRasterLayer>类。这里<QgsVectorLayer>是QGIS的核心类之一,用于加载和管理矢量数据。矢量数据以点、线、多边形等几何类型为基础,同时可以存储丰富的属性信息。该类支持加载多种矢量数据格式,如Shapefile、GeoJSON、PostGIS等,并提供对图层字段、几何和属性的全面操作能力。通过QgsVectorLayer,用户可以执行添加、删除、编辑要素的操作,还可以进行几何操作,如缓冲区分析、相交或合并等。为了支持多样化的渲染和显示效果,QgsVectorLayer还结合QgsRenderer和QgsSymbol提供丰富的样式设置能力,能够灵活渲染点、线、面等几何对象,是GIS矢量数据处理和可视化的核心组件。

<QgsRasterLayer>类是QGIS中用于加载和管理栅格数据的关键类,栅格数据通常由像素格网组成,每个像素具有一个或多个数值(如影像亮度值、海拔高度值等)。该类支持多种栅格数据格式,如GeoTIFF、JPEG、PNG,以及基于服务的栅格源(如WMS和WMTS)。通过QgsRasterLayer,用户可以对栅格数据进行基本的可视化设置,如指定颜色渲染方式、调整波段组合和透明度等。它还支持与其他工具结合,执行栅格数据的裁剪、重投影、统计分析等操作,是GIS栅格数据加载、管理和渲染的主要工具。

< QgsVectorLayer >类的继承关系如图4.2.1-1所示。

图4.2.1-1 < QgsVectorLayer >类的继承关系

与之相搭配的,< QgsRasterLayer >类的继承关系如图4.2.1-2所示。

图4.2.1-2 < QgsRasterLayer >类的继承关系

接下来我们就如何实现基于QGIS二次开发实现GIS矢量数据编辑操作给出详细过程。

4.2.2 GIS矢量数据编辑实现过程

这里我们首先打开项目的ui文件,在主界面添加需要使用的QAction控件,分别为“打开工程”、“添加矢量数据”、“添加栅格数据”、“打开属性表”和“打开属性管理器”。为了便于代码的编辑,将添加的按钮的objectName分别命名为“actionOpenProject”、“actionAddVectorData”、“actionAddRasterData”、“actionOpenFields”和“actionOpenAttrTable”。操作如图4.2.2-1所示。

图4.2.2-1 对ui进行操作

将设定的ui进行保存后,即可回到Visual Studio中,对相应的代码进行适当的编辑。

一、打开文件的实现

首先,需要进入头文件中,定义必要的函数,这是由于QT的信号与槽的机制,必须要进行信号与槽的相关绑定,这里我们主要预先声明了一个函数,即“on_actionOpenProject_triggered()”。如图4.2.2-2所示。

图4.2.2-2 声明函数

接下来,需要对声明的函数进行详细的定义。“on_actionOpenProject_triggered()”函数主要用于打开一个 QGIS 工程文件(.qgs),加载其图层到项目中,并创建一个新的 QgsLayerTreeMapCanvasBridge 对象,将工程的图层树与地图画布关联,实现图层的同步渲染与显示。

操作如图4.2.2-3所示。

图4.2.2-3 定义函数

二、矢量和栅格文件读取的实现

接下来,需要进入头文件中,定义必要的函数,这是由于QT的信号与槽的机制,必须要进行信号与槽的相关绑定,这里我们主要预先声明了两个函数,即“on_actionAddVectorData_triggered”和“on_actionAddRasterData_triggered”。如图4.2.2-4所示。

图4.2.2-4 声明函数

接下来,需要对声明的函数进行详细的定义。“on_actionAddVectorData_triggered()”函数用于加载用户选择的矢量数据(如 Shapefile),验证其有效性后添加到 QGIS 工程中,并更新地图画布显示,同时设置当前活动图层。

“on_actionAddRasterData_triggered()”函数用于加载用户选择的栅格数据(如 TIFF、IMG 文件),验证其有效性后将图层添加到 QGIS 工程,并刷新地图画布以显示新加载的图层。

操作如图4.2.2-5所示。

图4.2.2-5 定义函数

三、属性表和属性字段的实现

接下来,需要进入头文件中,定义必要的函数,这是由于QT的信号与槽的机制,必须要进行信号与槽的相关绑定,这里我们主要预先声明了两个函数,即“on_actionOpenAttrTable_triggered()”和“on_actionOpenFields_triggered()”。如图4.2.2-6所示。

图4.2.2-6 声明函数

接下来,需要对声明的函数进行详细的定义。“on_actionOpenAttrTable_triggered”函数用于打开当前矢量图层的属性表,检查图层有效性和要素数量后,创建属性表视图并加载所有要素数据,同时避免重复打开多个属性表窗口。

“on_actionOpenFields_triggered”函数用于打开当前矢量图层的字段结构编辑窗口,支持字段的查看和修改。如果字段窗口已存在,则直接激活,否则创建新的窗口并加载字段数据。

操作如图4.2.2-7所示。

图4.2.2-7 定义函数

进行完如上步骤,编译即可得到相应具备GIS矢量数据编辑功能的系统,如图4.2.2-8所示。

图4.2.2-8 系统界面

4.3 结果展示

完成4.2部分的系统构建后,我们便可以使用系统的GIS数据编辑功能了,点击“打开工程”,便可以选择打开一个QGIS的“.qgs”的工程项目。如图4.3-1所示。

图4.3-1 打开工程

这里我们也可以进行矢量数据的添加,这里可以通过点击菜单栏打开,同样也可以通过“添加栅格图层”点击界面的按钮进行打开,如图4.3-2所示。

图4.3-2 矢量数据的添加

当然,这里也可以显示 GeoTiff 格式的遥感影像或 DEM 数据,可以通过点击菜单栏“添加栅格图层”打开,同样也可以通过点击界面的按钮进行打开,如图4.3-3所示。

图4.3-3 栅格数据添加

同样,这里也可以显示矢量数据的属性结构,可以通过点击菜单栏“打开属性结构”打开,同样也可以通过点击界面的按钮进行打开如,图4.3-4所示。

图4.3-4 矢量数据的属性结构

同样,也可以显示属性字段,可以通过点击菜单栏“打开属性字段”打开,同样也可以通过点击界面的按钮进行打开如,如图4.3-5所示。

图4.3-5 显示属性字段

在打开的属性表中,也可以进行字段的添加,点击左上角的“添加字段”按钮即可完成字段的添加操作,如图4.3.6所示。

图4.3-6 字段属性修改

4.4 关键代码

这里的关键代码是针对GIS矢量数据编辑操作。

具体代码的功能主要是:“on_actionOpenProject_triggered()”函数主要用于打开一个 QGIS 工程文件(.qgs),加载其图层到项目中,并创建一个新的 QgsLayerTreeMapCanvasBridge 对象,将工程的图层树与地图画布关联,实现图层的同步渲染与显示。on_actionAddVectorData_triggered()”函数用于加载用户选择的矢量数据(如 Shapefile),验证其有效性后添加到 QGIS 工程中,并更新地图画布显示,同时设置当前活动图层。

“on_actionAddRasterData_triggered()”函数用于加载用户选择的栅格数据(如 TIFF、IMG 文件),验证其有效性后将图层添加到 QGIS 工程,并刷新地图画布以显示新加载的图层。

“on_actionOpenAttrTable_triggered”函数用于打开当前矢量图层的属性表,检查图层有效性和要素数量后,创建属性表视图并加载所有要素数据,同时避免重复打开多个属性表窗口。

“on_actionOpenFields_triggered”函数用于打开当前矢量图层的字段结构编辑窗口,支持字段的查看和修改。如果字段窗口已存在,则直接激活,否则创建新的窗口并加载字段数据。

源代码如下:

//打开qgs项目
void YLGIS::on_actionOpenProject_triggered()
{
	QString filename = QFileDialog::getOpenFileName(this, QStringLiteral("选择工程文件"), "", "QGIS project (*.qgs)");
	QFileInfo fi(filename);
	if (!fi.exists())
	{
		return;
	}
	QgsProject::instance()->read(filename);
	m_curMapLayer = QgsProject::instance()->mapLayer(0);
	// 删除已有的m_layerTreeCanvasBridge以防止重复实例化
	if (m_layerTreeCanvasBridge) {
		delete m_layerTreeCanvasBridge;
		m_layerTreeCanvasBridge = nullptr;
	}
	m_layerTreeCanvasBridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), m_mapCanvas, this);
}
//打开矢量文件
void YLGIS::on_actionAddVectorData_triggered()
{
	QStringList layerPathList = QFileDialog::getOpenFileNames(this, QStringLiteral("选择矢量数据"), "", "shapefile (*.shp)");
	QList<QgsMapLayer*> layerList;
	for (QString layerPath : layerPathList)
	{
		QFileInfo fi(layerPath);
		if (!fi.exists()) { return; }
		QString layerBaseName = fi.baseName(); // 图层名称
		QgsVectorLayer* vecLayer = new QgsVectorLayer(layerPath, layerBaseName);
		if (!vecLayer) { return; }
		if (!vecLayer->isValid())
		{
			QMessageBox::information(0, "", "layer is invalid");
			return;
		}
		layerList << vecLayer;
	}
	if (layerList.size() < 1)
		return;
	//选择图层
	connect(m_layerTreeView, &QgsLayerTreeView::currentLayerChanged, this, &YLGIS::onCurrentLayerChanged);
	m_curMapLayer = layerList[0];
	QgsProject::instance()->addMapLayers(layerList);
	m_mapCanvas->refresh();
}
//打开栅格文件
void YLGIS::on_actionAddRasterData_triggered()
{
	QStringList layerPathList = QFileDialog::getOpenFileNames(this, QStringLiteral("选择栅格数据"), "", "Image (*.img *.tif *.tiff)");
	QList<QgsMapLayer*> layerList;
	for (QString layerPath : layerPathList)
	{
		QFileInfo fi(layerPath);
		if (!fi.exists()) { return; }
		QString layerBaseName = fi.baseName(); // 图层名称
		QgsRasterLayer* rasterLayer = new QgsRasterLayer(layerPath, layerBaseName);
		if (!rasterLayer) { return; }
		if (!rasterLayer->isValid())
		{
			QMessageBox::information(0, "", "layer is invalid");
			return;
		}
		layerList << rasterLayer;
	}
	QgsProject::instance()->addMapLayers(layerList);
	m_mapCanvas->refresh();
}
//显示属性表
void YLGIS::on_actionOpenAttrTable_triggered()
{
	// 检查当前图层是否有效
	QgsVectorLayer* layer = (QgsVectorLayer*)m_curMapLayer;
	if (layer == nullptr || !layer->isValid() || QgsMapLayerType::VectorLayer != m_curMapLayer->type())
	{
		qDebug() << QStringLiteral("当前图层无效或不是矢量图层。");
		return;
	}
	// 检查图层是否有要素,若没有则提示
	if (layer->featureCount() == 0)
	{
		qDebug() << QStringLiteral("图层中没有要素数据。");
		return;
	}
	// 创建一个属性表缓存(缓存大小可根据图层要素数量调整)
	QgsVectorLayerCache* lc = new QgsVectorLayerCache(layer, 5000);
	// 创建属性表模型并加载图层数据
	QgsAttributeTableModel* tm = new QgsAttributeTableModel(lc);
	//if (!tm->loadLayer())  // 确保加载成功
	//{
	//	qDebug() << "属性表模型加载失败。";
	//	delete lc;
	//	delete tm;
	//	return;
	//}
	// 创建过滤模型,并设置为显示所有数据
	QgsAttributeTableFilterModel* tfm = new QgsAttributeTableFilterModel(m_mapCanvas, tm, tm);
	tfm->setFilterMode(QgsAttributeTableFilterModel::ShowAll);
	// 检查是否已经存在一个打开的属性表视图,避免重复打开
	static QgsAttributeTableView* tv = nullptr;
	if (tv)  // 如果已存在,则直接显示
	{
		tv->raise();
		tv->activateWindow();
		return;
	}
	// 创建并设置属性表视图
	tv = new QgsAttributeTableView();
	tv->setModel(tfm);
	// 显示属性表视图
	tv->show();
	tv->raise();
	tv->activateWindow();  // 将窗口置于前台
	// 在窗口关闭时,重置 tv 指针,确保下次可以重新创建
	connect(tv, &QgsAttributeTableView::destroyed, [=]() {
		tv = nullptr;
		});
}
//打开属性字段
void YLGIS::on_actionOpenFields_triggered()
{
	// 检查当前图层是否有效
	QgsVectorLayer* layer = (QgsVectorLayer*)m_curMapLayer;
	if (layer == nullptr || !layer->isValid() || QgsMapLayerType::VectorLayer != m_curMapLayer->type())
	{
		qDebug() << QStringLiteral("当前图层无效或不是矢量图层。");
		return;
	}
	// 启用编辑模式(如果未启动)
	if (!layer->isEditable())
	{
		layer->startEditing();
	}
	// 静态指针,确保只打开一个字段结构窗口
	static QgsSourceFieldsProperties* pWidget = nullptr;
	if (pWidget)  // 如果窗口已存在,则直接激活
	{
		pWidget->raise();
		pWidget->activateWindow();
		return;
	}
	// 创建属性结构窗口并加载字段数据
	pWidget = new QgsSourceFieldsProperties(layer, nullptr);
	pWidget->loadRows();
	// 显示窗口
	pWidget->show();
	pWidget->raise();
	pWidget->activateWindow();
	// 连接窗口销毁事件,窗口关闭时重置 pWidget 指针
	connect(pWidget, &QgsSourceFieldsProperties::destroyed, [=]() {
		pWidget = nullptr;
		});
}
Qgis二次开发-QgsMapTool地图交互工具详解 QgsMapTool地图工具是用于操作地图画布的用户交互式工具。例如,地图平移和缩放功能被实现为地图工具。QgsMapToolEdit:用于编辑矢量几何图形的映射工具的基类QgsMapToolEmitPoint:一个地图工具,当单击地图时,它只是发出一个点。将一个槽连接到它的canvasClicked()信号将允许您为传入点实现自定义行为。QgsMapToolExtent:地图画布上绘制矩形发出一个范围。QgsMapToolIdentify :用于识别图层特征的映射工具。 阅读详情

相关推荐

Qgis二次开发-实现缩略图、标注

因为上述动作是和画布进行交互,所以首先需要自定义一个地图交互工具类,由于做的比较简单,只需要重写实现鼠标点击事件。其次就是在地图画布上画标注图片(svg格式),以及缩略图片(其他格式的),以及经纬度坐标文字。以下是参考如何画svg标注,栅格图片,文字等。Qgis二次开发-QgsAnnotationItem(添加文字、图片标注(支持svg、png、jpg等常用图片格式))_Mr.codeee的博客-优快云博客首先说一下我遇到的问题,

希望能帮助大家,希望大家多多支持,你们的支持是我前进的动力。 3116

基于QGIS的二次开发(一):准备工作

因此,为了将逻辑与界面分离,我们需要继承这个代码里的对象,在继承对象中奖进行我们的逻辑代码编写,继承窗体类的代码如下所示,在此代码中我们创建了一个Ui_MainWindow 的子类MainWindow,其主体函数是调用构造函数,同时调用ui.py中的setupUi方法来构造整个界面,该文件命名为Ui_frm_main.py。在实验过程中,我们可以选择使用VS Code或者PyCharm作为我们的开发用IDE,此次实验中我选择使用的是较为熟悉且已安装完成的PyCharm。

m0_69187448的博客 6758

QGis二次开发基础 -- 添加矢量要素功能

矢量编辑的功能,是让GIS软件成为生产力工具所必备的基础功能。本文想跟大家探讨一下QGis二次开发中的添加矢量要素功能。 文章的示例工程地址在 https://github.com/Jacory/qgis_dev, 可fork自己的版本,并留意我不定时的更新 注意:本文开头部分代码比较多,篇幅比较长。虽然并非所有东西都与本文直接相关,但是我想通过前面的介绍,让大家对工具的功能实现有个基本的了解,

MrJGao的专栏 1万+

1. qgis二次开发环境搭建(qgis-3.28.6+qt5.15)

本文介绍了QGIS二次开发环境的搭建,完成了Ubuntu QGis3.28 Debug开发环境搭建,Window Release开发环境搭建

雷动专栏 7781

QGis 二次开发基础 -- 显示数据

写在前面,QGis源码编译请看这里 – QGis2.9.0源码编译及二次开发包下载,

MrJGao的专栏 2万+

QGis二次开发基础 -- 矢量图层的显示样式

带坐标的矢量图层作为GIS的核心数据,具有非常丰富的用途。人们往往喜欢在地图上做各种标记,不仅美观,而且使地图清晰,一目了然。于是应运而生了使用各种各样的图标作为地图标记的功能需求,在很多GIS软件上,这早已不是什么新鲜事了。然而在QGis二次开发的时候,同学们的对于图层样式自定义的需求貌似还挺大的,今天就来与大家探讨一下这个功能的实现。下面我将会很简略的介绍这个功能相关的类,并用一个简单的例子来展

MrJGao的专栏 1万+

【QGIS二次开发】地图编辑-09

该系列文章详细介绍了QGIS二次开发中的地图显示、交互、编辑等功能。主要内容包括:1)地图加载与图层管理,通过代码实现地图显示与图层交互;2)地图符号与色表设置,优化地图可视化效果;3)地图编辑功能,支持属性表结构查看、属性编辑、表格文件转矢量等操作,并提供了相关代码实现;4)撤销与重做功能,通过QUndoStack实现图层编辑的撤销与重做操作。文章通过代码示例和逻辑分析,帮助开发者理解并实现QGIS二次开发中的核心功能,适用于地理信息系统开发人员参考。

HenryAnChen的博客 1113

QGIS二次开发入坑指南

日前由于项目需求,学习了QGIS,并在QGIS上进行二次开发。在这里记录一下到目前为止的——入坑过程。 下载QGIS 下载QGIS可以从官网上直接下载。首先,我也是想着编译一下源码,从源码学习。当我开始下载源码之后,并按照网上的一系列教程开始编译时,到目前为止,我还没有成功过。都是在VS中编译时报各种错误。所以,本文不介绍源码编译。当我哪天成功了,我再来补充。 下面介绍一下我所使用的环境...

爱明爱夏的博客 2万+

【QGIS二次开发】地图编辑-08

该系列文章详细介绍了QGIS二次开发中的地图显示、交互、编辑等功能。

HenryAnChen的博客 1235

004 在QGIS中使用矢量数据

矢量数据(Vector Data)是用X、Y、Z坐标表示地图图形或地理实体位置的数据。矢量数据一般通过记录坐标的方式来 尽可能将地理实体的空间位置表现的精确。常见的矢量数据有:点、线、面等格式。QGIS可以支持多种的矢量数据,如常见的 Shapefile 和 MapInfo MIF、TAB;另外 QGIS 亦支持在 PostgreSQL 数据库中的 PostGIS 图层;以及提供 CSV(delimited text)纯文本导入。

qq_35662333的博客 1914

GIS开发:QGIS编辑矢量数据

地图开发或者展示类的开发中,涉及到行政区划、道路等空间地理信息,对于非专业的GIS人员,一般都是去互联网上搜索对应的数据,直接拿过来使用,要求的格式是GEOJSON,这也是比较通用的,容易进行数据使用,要是拿来个ESRI shapefile,还需要类库进行处理,或者在线提供各种转换的网站,将数据转换GEOJSON。 专业的GIS人员一般都能够对空间数据进行一定的处理,常用的GIS工具是Arcgis软件,所支持的空间数据类型也很多,功能也很强大,但是Arcgis软件安装和占用空间也是很大的,而且简单的空间数据

地理信息技术杂谈 博客,欢迎技术交流 5306

Qt+QGis二次开发:矢量图层的显示样式

原文链接:QGis二次开发基础 -- 矢量图层的显示样式 转载于:https://www.cnblogs.com/rainbow70626/p/10380534.html

weixin_30390075的博客 694

QGis二次开发基础 -- 构建图层管理器

为了回应有些同学对上一篇博文的建议,这篇文章主要关注于QGis二次开发中的“图层管理器”的实现。使用QGis构建独立应用系统,我相信大部分同学应该还是关注于GIS基本功能框架构建上,也就是一些基本的GIS功能,例如: 数据的显示、漫游浏览等 读入数据的管理,也就是“图层管理器”功能 数据基本信息的查询,例如空间坐标、投影查询,属性表查询等 数据编辑,包括对属性表的编辑和矢量文件形状的编辑等 虽然各个

MrJGao的专栏 1万+

QGIS操作教程 | 一站式从入门到精通的QGIS学习指南

QGIS操作教程是一个系统性的开源GIS学习网站,提供从基础到进阶的完整教学体系。基础教程包含软件概览、安装配置、数据管理、图层编辑、样式渲染等8大模块;进阶教程涵盖Python二次开发、处理工具箱和模型构建等高级功能。该教程特色鲜明:体系化教学、实用案例驱动、内容全面覆盖、图文并茂展示,适合GIS初学者、从业人员、开发者及行业用户学习。基于QGIS 3.34.0版本编写,完全免费开放,帮助用户从零成长为QGIS专家。

LZUGIS 1877

QGIS教程 加载shape数据 矢量数据(批量)

界面如下。

weixin_39676449的博客 5910

QGis二次开发基础 -- 文字标注

Label 这个功能是为了更直观的将矢量数据的属性信息显示在地图上,方便用户在浏览地图的时候查看。几乎每个 Gis 系统都会有这个基础功能,QGis 的 Label 更是非常漂亮,不仅支持标注的轮廓缓冲区功能,还可以给标注绘制上阴影效果等。今天就来说一说 QGis 二次开发中的文字标注功能的实现。

MrJGao的专栏 1万+

《QGIS基本功》即将启动原创

“QGIS课堂”公众号创建已满两个月,完成了20篇推送(含本篇),平均三天多一篇,文章质量和数量只能说是差强人意,还有很大提升空间。 相比于我们的平凡,“QGIS课堂”获得的关注则称得上惊喜。在没有做任何推广的情况下,短短两个月时间,“QGIS课堂”就迎来了400多位朋友。我们倍感欣慰,觉得所有的付出都是超值的。开源的精髓在于奉献,而奉献的过程其实就是自我提升的过程。说实话,如果不是这么多朋友的支持与鼓励,我们恐怕很难有勇气坚持走下去,更不用说迎接更大的挑战。感谢所有关注“QGIS课堂”的朋友们! 这段时间

QGISClass的博客 566

QGIS 示例程序,实现QGIS二次开发

本人编写的QGIS示例程序,环境vc9,qgis1.6 sdk,qt4.7,实现了基本的gis功能。

上一篇: QGIS二次开发(地图符号库操作)
下一篇: QGIS二次开发(GIS投影变换)
CUGLin
博客等级 码龄4年 585粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值