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

实习四 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 矢量数据追加到 PostgreSQL 数据库 为了将 QGIS 中的矢量数据成功导入并追加至 PostgreSQL 数据库,需先确认 PostgreSQL 已安装 PostGIS 扩展。这一步骤通过 SQL 命令 `CREATE EXTENSION postgis;` 完成[^1]。 #### 准备工作 确保 PostgreSQL 和 PostGIS 正常运行,并已创建目标数据库以及启用了 PostGIS 支持。 #### 方法一:使用 DB Manager 插件 QGIS 自带的 DB Manager 是一种便捷的方式用于管理不同类型的地理空间数据库,包括 PostgreSQL/PostGIS。 - **打开DB Manager** - 在菜单栏选择 `Database -> DB Manager -> DB Manager` - **连接到 PostgreSQL 数据库** - 进入 DB Manager 后点击左侧面板上的 “Connect to database”,输入相应参数建立与 PostgreSQL 的连接 - **加载图层** - 成功连接之后,在右侧窗口中找到要保存的空间表位置;右键单击该节点选择 "Import Layer/File" - **配置选项** - 浏览选取待上传的文件路径,设置编码方式、SRID(坐标参照系)、几何字段名称等必要属性 ```sql INSERT INTO schema_name.table_name (column_names, geom_column) SELECT column_names, ST_Transform(geometry_column, target_srid) AS geom_transformed FROM source_table; ``` 此命令展示了如何向现有表格插入新记录的同时转换几何对象的投影系统。 #### 方法二:利用 Processing Toolbox Processing Toolbox 提供了一个图形化界面来处理各种 GIS 操作流程,其中包括导出功能可以直接把当前活动图层发送给指定的目标存储介质如 PostgreSQL。 - **启动 Processing Toolbox** - 调用方法为 `Processing -> Toolbox...` - **查找合适的算法** - 输入关键词 'export' 或者浏览供应商列表下的 QGIS Vector Database Tools 寻找适合的任务项 - **执行任务** - 设置好源图层和目的地详情后提交作业即可完成迁移过程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值