QGIS3.28的二次开发七:创建地图工具

news/2025/3/31 20:21:31/

地图工具是输入设备(一般指鼠标与键盘)与画布(QgsMapCanvas)的交互接口。它负责处理所有用户通过输入设备(鼠标和键盘)和画布互动的操作,例如镜头控制、要素绘制、标识工具等。

QgsMapTool 是地图工具的基类,继承自QObject,提供了地图工具和画布交互的基本接口,地图工具子类通过重写这些虚函数接口实现自己的独特功能,例如

  • 鼠标在画布上按下的 void QgsMapTool::canvasPressEvent(QgsMapMouseEvent * e)和释放的void QgsMapTool::canvasReleaseEvent(QgsMapMouseEvent * e)
  • 鼠标在画布上移动 void QgsMapTool::canvasMoveEvent(QgsMapMouseEvent * e)
  • 鼠标在画布上双击 void QgsMapTool::canvasDoubleClickEvent(QgsMapMouseEvent * e)
  • 键盘按键按下 void QgsMapTool::keyPressEvent(QKeyEvent * e) 和键盘按键释放 void QgsMapTool::keyReleaseEvent(QKeyEvent * e) (工具激活时)
  • 自定义右键菜单 void QgsMapTool::populateContextMenu(QMenu * menu)

 一张画布,即一个QgsMapCanvas实例,在同一时刻仅允许一个地图工具处于“激活”状态。通过继承该基类,QGIS 自己实现了部分地图工具。我们也可以继承QgsMapTool基类来实现自定义地图工具。

我们这里写段代码测试一下QGIS的三个地图工具,分别为

QgsMapToolPan 用于平移地图的地图工具。

QgsMapToolEmitPoint 使用此工具当单击地图时,它只是发出一个点。将一个槽连接到它的canvasClicked()信号可以为传入点实现自定义行为。

QgsMapToolIdentify 用于识别图层特征的地图工具。使用此工具当单击地图时选择一个点,进行识别:对于栅格层显示底层像素值,对于矢量层显示搜索半径内的特征属性(当矢量层处于编辑模式时允许编辑值)。我们用它下面的继承类QgsMapToolIdentifyFeature来写代码。

QgsMapToolIdentifyFeature 继承自上面的QgsMapToolIdentify,用于识别所选层上的特征。用户可以单击地图来自动识别这块区域具有的特征,然后会发出一个信号。

我们为了能清楚看到点击的是地图的哪块区域,需要将这块点击的区域高亮显示,用到的类为QgsHighlight 该类提供了一个透明的覆盖画布项,用于突出显示地图画布上的特征或几何图形。

例如这样可以设置我们的地图某块区域高亮为红色

color = QColor(Qt.red)
highlight = QgsHighlight(mapCanvas, feature, layer)
highlight.setColor(color)
color.setAlpha(50)    // 设置颜色透明度,0-255越小越透明
highlight.setFillColor(color)
highlight.show()

我们先看看运行效果

完整代码如下:

main.cpp

#include "qgis03_MapTools.h"
#include <QtWidgets/QApplication>
#include <qgsapplication.h>
#include <qgsproviderregistry.h>int main(int argc, char *argv[])
{QgsApplication a(argc, argv, true);// 设置并检查数据插件目录QgsProviderRegistry::instance("D:\\OSGeo4W\\apps\\qgis-ltr\\plugins");// 设置 GDAL 数据目录环境变量qputenv("GDAL_DATA", "D:\\OSGeo4W\\apps\\gdal\\share\\gdal");// 实例化一个qgis30_MapTools窗口qgis03_MapTools w;// 展示窗口w.show();return a.exec();
}

qgis03_MapTools.h

#pragma once#include <QtWidgets/QMainWindow>	// 继承自QMainWindow
#include "ui_qgis03_MapTools.h"	// UI界面的头文件
#include <qgsmapcanvas.h>	// 创建画布
#include <qgsmaptoolpan.h> // 移动地图
#include <qgsmaptoolemitpoint.h>	// 单击发出一个点,自定义槽函数实现行为
#include <qgsmaptoolidentifyfeature.h>	// 单击地图,识别选择图层的特征
#include <qgshighlight.h>	// 高亮显示某块地图class qgis03_MapTools : public QMainWindow
{Q_OBJECTpublic:qgis03_MapTools(QWidget *parent = Q_NULLPTR);private:Ui::qgis03_MapToolsClass ui;	// 示例化一个UI对象// 画布QgsMapCanvas mCanvas;// 漫游工具QgsMapToolPan mToolPan;// 产生点工具QgsMapToolEmitPoint mToolEmitPoint;// 标识工具QgsMapToolIdentifyFeature mToolIdentifyFeature;// 高亮对象(用于在地图上标出被标识工具选中的要素)QgsHighlight* mpHighlight = nullptr;// 地图工具切换选择槽void onMapToolSelected(bool isChecked);// 清除高亮对象槽void clearHighlight();
};

qgis03_MapTools.cpp

#include "qgis03_MapTools.h"
#include <qgsvectorlayer.h>
#include <qmessagebox.h>
#include <qgspointxy.h>	// 表示严格的二维位置,只有X和Y坐标
#include <qgsfeature.h>	// 封装了一个特性,包括它唯一的ID、几何形状和字段/值属性列表
#include <qgis.h>	// 提供了在整个应用程序中使用的全局常量
#include <qgsfield.h>	// 矢量图层的属性字段容器qgis03_MapTools::qgis03_MapTools(QWidget *parent): QMainWindow(parent),mCanvas(this),	// QgsMapCanvas	(QWidget * parent = nullptr)	mToolPan(&mCanvas),	// QgsMapToolPan (QgsMapCanvas *canvas)mToolEmitPoint(&mCanvas),	// QgsMapToolEmitPoint (QgsMapCanvas *canvas)mToolIdentifyFeature(&mCanvas)	// QgsMapToolIdentifyFeature(QgsMapCanvas * canvas,	QgsVectorLayer * vl = nullptr)
{ui.setupUi(this);// 在主窗体的竖直布局最后添加画布组件ui.verticalLayout->addWidget(&mCanvas);// 新建矢量图层QgsVectorLayer* pVectorLayer = new QgsVectorLayer("E:\\TestImage\\全国省界\\全国省界.shp", "全国省界");// 将新建的矢量图层添加到画布mCanvas.setLayers(QList<QgsMapLayer*>() << pVectorLayer);// 缩放到全图mCanvas.zoomToFullExtent();// 自定义QgsMapToolEmitPoint的槽函数,显示一个弹出消息,显示所点击的点位置// void QgsMapToolEmitPoint::canvasClicked(const QgsPointXY & point,Qt::MouseButton button)QObject::connect(&mToolEmitPoint, &QgsMapToolEmitPoint::canvasClicked, [=](const QgsPointXY & point, Qt::MouseButton button) {QMessageBox::information(this, "QgsMapToolEmitPoint", QString("X: %1\nY: %2").arg(QString::number(point.x()), QString::number(point.y())));});// 设定QgsMapToolIdentifyFeature工具识别的目标图层mToolIdentifyFeature.setLayer(pVectorLayer);// 自定义QgsMapToolIdentifyFeature工具点击后的槽函数// QgsMapToolIdentifyFeature::featureIdentified信号被重载,要用如下方式来写QObject::connect(&mToolIdentifyFeature,static_cast<void (QgsMapToolIdentifyFeature::*)(const QgsFeature &)>(&QgsMapToolIdentifyFeature::featureIdentified), [=](const QgsFeature &feature) {// 清除高亮clearHighlight();// 设置高亮对象mpHighlight = new QgsHighlight(&mCanvas, feature.geometry(), pVectorLayer);// 设置高亮颜色 DEFAULT_HIGHLIGHT_COLOR = QColor( 255, 0, 0, 128 ), RGBA格式QColor color = QColor(Qgis::DEFAULT_HIGHLIGHT_COLOR.name());// 设置高亮颜色透明度color.setAlpha(Qgis::DEFAULT_HIGHLIGHT_COLOR.alpha());mpHighlight->setColor(color);	// 设置线条/描边颜色mpHighlight->setFillColor(color);	// 填充颜色// DEFAULT_HIGHLIGHT_BUFFER_MM = 0.5mpHighlight->setBuffer(Qgis::DEFAULT_HIGHLIGHT_BUFFER_MM);	// 设置行/行程缓冲以毫米为单位// DEFAULT_HIGHLIGHT_MIN_WIDTH_MM = 1.0mpHighlight->setMinWidth(Qgis::DEFAULT_HIGHLIGHT_MIN_WIDTH_MM);	// 设置最小线/笔画宽度,以毫米为单位QString msg;QgsFields fields = feature.fields();	// QgsFeature.fields()返回与该特性关联的字段映射(不包含属性值)// qDebug() << fields.names();	// 打印字段名// qDebug() << feature.fields().names();	// 打印字段名for (int i = 0; i < fields.count(); i++){// QgsFields.at(int i)返回特定索引处的字段// QgsFeature.attribute(int fieldIdx) 从其索引查找属性值msg += QString("%1: %2\n").arg(fields.at(i).name(), feature.attribute(i).toString());}// 这样写也可以/*	for (int i = 0; i < feature.fields().count(); i++){msg += QString("%1:%2\n").arg(feature.fields().names()[i], feature.attribute(i).toString());}*/QMessageBox::information(this, "QgsMapToolIdentifyFeature", msg);});// 工具单选框的选择信号QObject::connect(ui.radPan, &QRadioButton::toggled, this, &qgis03_MapTools::onMapToolSelected);QObject::connect(ui.radEmitPoint, &QRadioButton::toggled, this, &qgis03_MapTools::onMapToolSelected);QObject::connect(ui.radIdentifyFeature, &QRadioButton::toggled, this, &qgis03_MapTools::onMapToolSelected);
}// 将地图工具和UI界面的按钮绑定
void qgis03_MapTools::onMapToolSelected(bool checked)
{// 如果按钮被选中,则checked为true,否则为falseif (checked)	// 其实在这里,if可以忽略{// 清除上一次标识操作留下的高亮clearHighlight();// 根据点选的单选框,激活相应的工具// 注意 QgsMapCanvas 一次只允许有一个工具激活if (ui.radPan->isChecked()){// 设置画布当前正在被使用的地图工具,void QgsMapCanvas::setMapTool(QgsMapTool * mapTool,bool clean = false)mCanvas.setMapTool(&mToolPan);}else if (ui.radEmitPoint->isChecked()){mCanvas.setMapTool(&mToolEmitPoint);}else if (ui.radIdentifyFeature->isChecked()){mCanvas.setMapTool(&mToolIdentifyFeature);}}
}// 清除高亮对象
void qgis03_MapTools::clearHighlight()
{// 如果高亮对象不为空,则删除该对象if (mpHighlight){delete mpHighlight;}// 使mpHighlight指向nullptrmpHighlight = nullptr;
}

 qgis03_MapTools.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>qgis03_MapToolsClass</class><widget class="QMainWindow" name="qgis03_MapToolsClass"><property name="geometry"><rect><x>0</x><y>0</y><width>600</width><height>400</height></rect></property><property name="windowTitle"><string>qgis03_地图工具</string></property><widget class="QWidget" name="centralWidget"><layout class="QVBoxLayout" name="verticalLayout"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QRadioButton" name="radPan"><property name="text"><string>QgsMapToolPan</string></property></widget></item><item><widget class="QRadioButton" name="radEmitPoint"><property name="text"><string>QgsMapToolEmitPoint</string></property></widget></item><item><widget class="QRadioButton" name="radIdentifyFeature"><property name="text"><string>QgsMapToolIdentifyFeature</string></property></widget></item><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></item></layout></widget><widget class="QMenuBar" name="menuBar"><property name="geometry"><rect><x>0</x><y>0</y><width>600</width><height>23</height></rect></property></widget><widget class="QToolBar" name="mainToolBar"><attribute name="toolBarArea"><enum>TopToolBarArea</enum></attribute><attribute name="toolBarBreak"><bool>false</bool></attribute></widget><widget class="QStatusBar" name="statusBar"/></widget><layoutdefault spacing="6" margin="11"/><resources><include location="qgis03_MapTools.qrc"/></resources><connections/>
</ui>

参考文章 文章页 | mriiiron's blog


http://www.ppmy.cn/news/1027603.html

相关文章

Spannable配合AnimationDrawable实现TextView中展示Gif图片

辣的原理解释&#xff0c;反正大家也不爱看&#xff0c;所以直接上代码了 长这样&#xff0c;下面两个图是gif&#xff0c;会动的。 package com.example.myapplication;import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable…

Linux 终端命令之文件浏览(2) more

Linux 文件浏览命令 cat, more, less, head, tail&#xff0c;此五个文件浏览类的命令皆为外部命令。 hannHannYang:~$ which cat /usr/bin/cat hannHannYang:~$ which more /usr/bin/more hannHannYang:~$ which less /usr/bin/less hannHannYang:~$ which head /usr/bin/he…

c语言——斐波那契数列应用

//斐波那契数列应用 #include<stdio.h> int main() {int i,n,t10,t21,nextTerm;printf("输出项目数&#xff1a;");scanf("%d",&n);printf("斐波那契数列应用&#xff1a;");for(i1;i<n;i){printf("%d、",t1);nextTermt1…

RTT(RT-Thread)线程间同步(保姆级)

目录 线程间同步 信号量 信号量结构体 信号量的使用和管理 动态创建信号量 实例 静态创建信号量 初始化和脱离信号量 获取信号量 信号量的互斥操作 获取信号量函数 释放信号量 信号量同步实例 互斥量&#xff08;互斥锁&#xff09; 互斥量的使用和管理 动态创…

LTE和5G无线技术对比简介

LTE和5G是两种不同的无线通信技术&#xff0c;它们在速度、延迟、容量、覆盖范围和设备兼容性等方面存在差异。 LTE&#xff0c;即长期演进技术&#xff0c;是一种基于OFDMA的4G蜂窝网络标准&#xff0c;由3GPP组织制定并发布。它的主要目的是改进3G的空中接入技术&#xff0c;…

数据库事务ACID介绍

一、ACID简介 ACID&#xff0c;是指数据库管理系统&#xff08;DBMS&#xff09;在增删改数据的的过程中&#xff0c;为保证事务&#xff08;transaction&#xff09;的准确性&#xff0c;可靠性等&#xff0c;所必须具备的四个特性&#xff1a;原子性&#xff08;atomicity&a…

MATLAB计算连续月份的不同栅格数据间的相关系数(输出为tif影像)

%先导入投影信息&#xff0c;某个影像的路径就行&#xff08;最好是你分析的数据中的一个&#xff09; [a,R]readgeoraster(G:\SIF\Global-AI_monthly_v3\bi\199001.tif); infogeotiffinfo(G:\SIF\Global-AI_monthly_v3\bi\199001.tif); [m,n]size(a); i1;gwzeros(m*n,24); %此…

侯捷 C++ part2 兼谈对象模型笔记——3 模板

3 模板 3.1 类模板/函数模板 补充&#xff1a;只有模板的尖括号中<>&#xff0c;关键字 typename 和 class 是一样的 3.2 成员模板 它即是模板的一部分&#xff0c;自己又是模板&#xff0c;则称为成员模板 其经常用于构造函数 ctor1 这是默认构造函数的实现&#…