Qgis二次开发-QgsMapTool地图交互工具详解

这篇具有很好参考价值的文章主要介绍了Qgis二次开发-QgsMapTool地图交互工具详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.简介

QgsMapTool地图工具是用于操作地图画布的用户交互式工具。例如,地图平移和缩放功能被实现为地图工具。

QgsMapTool是抽象基类,以下是类的继承关系:

Qgis二次开发-QgsMapTool地图交互工具详解,Qgis,qt,qgis,QgsMapTool,地图交互

  • QgsMapToolEdit:用于编辑矢量几何图形的映射工具的基类 
  • QgsMapToolEmitPoint:一个地图工具,当单击地图时,它只是发出一个点。
    将一个槽连接到它的canvasClicked()信号将允许您为传入点实现自定义行为。
  • QgsMapToolExtent:地图画布上绘制矩形发出一个范围。
  • QgsMapToolIdentify :用于识别图层特征的映射工具。
  • QgsMapToolPan:用于平移地图的地图工具。
  • QgsMapToolZoom :用于放大/缩小地图的地图工具。

2.常用接口

virtual void canvasDoubleClickEvent (QgsMapMouseEvent *e) 重写鼠标双击事件
virtual void canvasMoveEvent (QgsMapMouseEvent *e) 重写鼠标移动事件
virtual void canvasPressEvent (QgsMapMouseEvent *e) 重写鼠标按下事件
virtual void canvasReleaseEvent (QgsMapMouseEvent *e) 重写鼠标抬起事件
virtual void setCursor (const QCursor &cursor) 设置光标
QgsPointXY toMapCoordinates (QPoint point) 将点从屏幕坐标转换为地图坐标。

3.示例 

示例1:画布移动、放大、缩小

Qgis二次开发-QgsMapTool地图交互工具详解,Qgis,qt,qgis,QgsMapTool,地图交互

源码:

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_GisCtrl.h"
#include <QDebug>
#include <QFileInfo>
#include <qgsmaptoolpan.h>
#include <qgsrasterlayer.h>
#include <qgsmapcanvas.h>
#include <qgspoint.h>
#include <QMouseEvent>
#include <qgsmaptoolzoom.h>
#include <QActionGroup>

class GisCtrl : public QMainWindow
{
    Q_OBJECT

public:
    GisCtrl(QWidget *parent = Q_NULLPTR);

private:
    Ui::GisCtrlClass ui;

private slots:
	void slotXyCoordinates(const QgsPointXY &p);
	void slotMove();
	void slotZoomIn();
	void slotZoomOut();

private:
	QgsMapCanvas *m_mapCanvas = nullptr;
	QList<QgsMapLayer *> m_layers;
	QgsMapToolPan *m_toolPan = nullptr;	// 新建移动工具
	QgsMapToolZoom *m_toolZoomIn = nullptr;//放大
	QgsMapToolZoom *m_toolZoomOut = nullptr;//缩小

	QActionGroup *m_actionGroup = nullptr;
};



#include "GisCtrl.h"
#include <qgsrasterlayer.h>
#include <qgsrubberband.h>
#pragma execution_character_set("utf-8")

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

	//创建画布
	m_mapCanvas = new QgsMapCanvas(this);

	QString url = "F:/arcgis/TMS.xml";

	m_mapCanvas->setCanvasColor(QColor(255, 255, 255));

	//加载瓦片地图
	QgsRasterLayer *layer = new QgsRasterLayer(url);
	if (!layer->isValid())
	{
		qDebug() << "load map faild";
	}

	m_layers.append(layer);

	// 新建移动工具
	m_toolPan = new QgsMapToolPan(m_mapCanvas);

	m_mapCanvas->setExtent(layer->extent());
	m_mapCanvas->enableAntiAliasing(true);
	m_mapCanvas->setLayers(m_layers);
	m_mapCanvas->setMapTool(m_toolPan);

	m_toolZoomIn = new QgsMapToolZoom(m_mapCanvas, false);
	m_toolZoomOut = new QgsMapToolZoom(m_mapCanvas, true);

	m_actionGroup = new QActionGroup(this);
	m_actionGroup->addAction(ui.actionMove);
	m_actionGroup->addAction(ui.actionZoomIn);
	m_actionGroup->addAction(ui.actionZoomOut);
	m_actionGroup->setExclusive(true);

	connect(m_mapCanvas, &QgsMapCanvas::xyCoordinates, this, &GisCtrl::slotXyCoordinates);
	connect(ui.actionMove, &QAction::triggered, this, &GisCtrl::slotMove);
	connect(ui.actionZoomIn, &QAction::triggered, this, &GisCtrl::slotZoomIn);
	connect(ui.actionZoomOut, &QAction::triggered, this, &GisCtrl::slotZoomOut);

	setCentralWidget(m_mapCanvas);

	ui.actionMove->setChecked(true);
	ui.actionLineManager->setVisible(false);
	ui.actionLayer->setVisible(false);
	ui.actionSelect->setVisible(false);
	ui.actionItem->setVisible(false);
}

void GisCtrl::slotXyCoordinates(const QgsPointXY &p)
{
	QString str = QString("经度= %1,纬度=%2").arg(QString::number(p.x(), 'f', 6)).arg(QString::number(p.y(), 'f', 6));
	this->statusBar()->showMessage(str);
}

void GisCtrl::slotMove()
{
	m_mapCanvas->setMapTool(m_toolPan);
}

void GisCtrl::slotZoomIn()
{
	m_mapCanvas->setMapTool(m_toolZoomIn);
}

void GisCtrl::slotZoomOut()
{
	m_mapCanvas->setMapTool(m_toolZoomOut);
}

示例2:鼠标点击画矩形。

Qgis二次开发-QgsMapTool地图交互工具详解,Qgis,qt,qgis,QgsMapTool,地图交互

自定义一个地图交互工具继承QgsMapToolIdentify

源码:

#pragma once
#include <QObject>
#include <QList>
#include <QScopedPointer>
#include <qgsmapcanvas.h>
#include <qgsmaptoolidentify.h>
#include <qgsrubberband.h>
#include <qgsmapmouseevent.h>


class QgsMapToolSelectFeatures : public QgsMapToolIdentify
{
	Q_OBJECT
public:
	QgsMapToolSelectFeatures(QgsMapCanvas *mapCanvas);

protected:
	//重写鼠标移动
	void canvasMoveEvent(QgsMapMouseEvent *e) override;
	//重写鼠标按下
	void canvasPressEvent(QgsMapMouseEvent *e) override;

	void initRubberBand();

private:
	// 是否正在选择
	bool mSelectionActive = false;
	QScopedPointer<QgsRubberBand> mSelectionRubberBand;
	QColor mFillColor = QColor(255, 255, 0, 63);
	QColor mStrokeColor = QColor(255, 255, 0, 100);
	QPoint mInitDragPos;
};


//cpp
#include "QgsMapToolSelectFeatures.h"
#include "QgsMapToolIdentify.h"

QgsMapToolSelectFeatures::QgsMapToolSelectFeatures(QgsMapCanvas *mapCanvas)
	: QgsMapToolIdentify(mapCanvas)
{
}

void QgsMapToolSelectFeatures::canvasMoveEvent(QgsMapMouseEvent * e)
{
	if (e->buttons() != Qt::LeftButton)
		return;

	QRect rect;
	if (!mSelectionActive)
	{
		mSelectionActive = true;
		rect = QRect(e->pos(), e->pos());
	}
	else
	{
		rect = QRect(e->pos(), mInitDragPos);
	}
	if (mSelectionRubberBand)
		mSelectionRubberBand->setToCanvasRectangle(rect);
}

void QgsMapToolSelectFeatures::canvasPressEvent(QgsMapMouseEvent * e)
{
	if (!mSelectionRubberBand)
		initRubberBand();

	mInitDragPos = e->pos();
}

void QgsMapToolSelectFeatures::initRubberBand()
{
	mSelectionRubberBand.reset(new QgsRubberBand(mCanvas, QgsWkbTypes::PolygonGeometry));
	mSelectionRubberBand->setFillColor(mFillColor);
	mSelectionRubberBand->setStrokeColor(mStrokeColor);
}

使用

QgsMapToolSelectFeatures *m_tool = new QgsMapToolSelectFeatures(m_mapCanvas);
m_mapCanvas->setMapTool(m_tool);

示例3:右键弹出菜单标注地点。

Qgis二次开发-QgsMapTool地图交互工具详解,Qgis,qt,qgis,QgsMapTool,地图交互

#pragma once
#include <QObject>
#include <QList>
#include <QScopedPointer>
#include <qmath.h>
#include <qgsmapcanvas.h>
#include <qgsmaptoolidentify.h>
#include <qgsrubberband.h>
#include <qgsmapmouseevent.h>
#include <qgsgeometry.h>
#include <QMenu>

class QgsRubberBand;
class QgsAnnotationPointTextItem;
class QgsMapToolAddItem : public QgsMapToolIdentify
{
	Q_OBJECT
public:
	QgsMapToolAddItem(QgsMapCanvas *mapCanvas);

	typedef struct _mark
	{
		QgsRubberBand *rubberBand;	//svg图标item
		QgsGeometry geo;				//区域
		QgsAnnotationPointTextItem *text;//字体
		QgsAnnotationLayer *layer;
	}Mark;

protected:
	//重写鼠标按下
	void canvasPressEvent(QgsMapMouseEvent *e) override;

private slots:
	void slotAdd();
	void slotDel();
	void slotShowScale(double scale);
	void slotZoomLastStatusChanged(bool);

private:
	// 是否正在选择
	bool mSelectionActive = false;

	QMenu *m_menu = nullptr;

	QAction *m_add = nullptr;
	QAction *m_del = nullptr;

	QgsMapCanvas *m_canvas;

	QList<Mark> m_lstMark;
};


#include "QgsMapToolAddItem.h"
#include "QgsMapToolIdentify.h"
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include <QMessageBox>
#include <qgsfeature.h>
#include <qgsvectorlayer.h>
#include <qgsrectangle.h>
#include <QMouseEvent>
#include <QMessageBox>
#include "BaseFunc.h"
#include <qgsannotationlayer.h>
#include <qgsannotationpointtextitem.h>

#pragma execution_character_set("utf-8")

extern bool g_is3857crs;
extern QList<QgsMapLayer *> g_layers;

static QgsPointXY g_point;
static int g_index = -1;
QgsMapToolAddItem::QgsMapToolAddItem(QgsMapCanvas *mapCanvas)
	: QgsMapToolIdentify(mapCanvas)
	, m_canvas(mapCanvas)
{
	this->setCursor(Qt::CrossCursor);

	m_menu = new QMenu();
	m_add = m_menu->addAction(QIcon(QPixmap(":/GisCtrl/image/add.png")),"添加");
	m_del = m_menu->addAction(QIcon(QPixmap(":/GisCtrl/image/del.png")),"删除");

	connect(m_add, &QAction::triggered, this, &QgsMapToolAddItem::slotAdd);
	connect(m_del, &QAction::triggered, this, &QgsMapToolAddItem::slotDel);
	connect(mapCanvas, &QgsMapCanvas::zoomLastStatusChanged,
		this, &QgsMapToolAddItem::slotZoomLastStatusChanged);
}

void QgsMapToolAddItem::canvasPressEvent(QgsMapMouseEvent * e)
{
	if (e->buttons() == Qt::RightButton)
	{
		g_point = e->mapPoint();
		bool isHaveItem = false;
		const QgsMapToPixel *mtransform = m_canvas->getCoordinateTransform();
		for (int i = 0; i < m_lstMark.size(); i++)
		{
			Mark item = m_lstMark.at(i);
			QgsVector qgsVector;

			QgsPointXY p2 = item.geo.asPoint();
			QgsPointXY curPoint = mtransform->transform(g_point.x(), g_point.y());
			QgsPointXY itemPoint = mtransform->transform(p2.x(), p2.y());

			qgsVector = curPoint - itemPoint;

			if ((-10 < qgsVector.x() && qgsVector.x() < 15) &&
				(-10 < qgsVector.y() && qgsVector.y() < 15))
			{
				isHaveItem = true;
				g_index = i;
				break;
			}
		}

		if (!isHaveItem)
			g_index = -1;
	
		QPoint point = e->pos();
		point.setY(point.y() + 80);

		m_del->setVisible(isHaveItem);
	
		m_menu->exec(point);
	}
	else
	{
		m_menu->hide();
	}
}

void QgsMapToolAddItem::slotAdd()
{
	//添加点
	QgsRubberBand *rb = new QgsRubberBand(m_canvas, QgsWkbTypes::PointGeometry);
	//rb->setOpacity(0.8);
	rb->setIcon(QgsRubberBand::IconType::ICON_SVG);    //设置图标类型
	rb->setIconSize(5);														//设置图标尺寸 
	rb->setSvgIcon(":/GisCtrl/image/water.svg", QPoint(-16, -16));        //设置图标文件路径和偏移

	QgsGeometry geo = QgsGeometry::fromPointXY(g_point);	//经纬度
	rb->addGeometry(geo);                              //绘制
	
	//添加文字
	QgsCoordinateTransformContext coordinateTransformContext;
	//先构造出一个能加注记的图层
	QgsAnnotationLayer *textLayer = new QgsAnnotationLayer("annotationLayer",
		QgsAnnotationLayer::LayerOptions(coordinateTransformContext));

	double lon = 0, lat = 0;
	BaseFunc::WebMercatorToWGS84(g_point.x(), g_point.y(), &lon, &lat);

	//构造时传入地理坐标,有必要后期改成鼠标事件点击来创建QgsAnnotationMarkerItem
	const QgsMapToPixel *mtransform = m_canvas->getCoordinateTransform();
	//转换到屏幕坐标
	QgsPointXY offsetPoint = mtransform->transform(g_point.x(), g_point.y());
	int yOffset = 25;
	offsetPoint.setY(offsetPoint.y() + yOffset);
	//转回去到地图坐标
	offsetPoint = mtransform->toMapCoordinates(offsetPoint.x(), offsetPoint.y());

	QString showText = QString("%1,%2").arg(QString::number(lon, 'f', 6)).arg(QString::number(lat, 'f', 6));
	QgsAnnotationPointTextItem* textItem = new QgsAnnotationPointTextItem(showText, QgsPoint(offsetPoint.x(), offsetPoint.y()));
	textItem->setAlignment(Qt::AlignHCenter);
	QgsTextFormat format;
	QFont font;
	font.setBold(true);
	font.setPointSize(13);
	format.setFont(font);
	format.setColor(QColor(Qt::yellow));
	textItem->setFormat(format);
	textLayer->addItem(textItem);//画布添加Item

	Mark mark;
	mark.rubberBand = rb;
	mark.geo = geo;
	mark.text = textItem;
	mark.layer = textLayer;

	m_lstMark.append(mark);

	g_layers.push_front(textLayer);
	m_canvas->setLayers(g_layers);
	m_canvas->refresh();
}

void QgsMapToolAddItem::slotDel()
{
	if (g_index < 0)
		return;

	Mark mark = m_lstMark.at(g_index);
	g_layers.removeOne(mark.layer);

	delete mark.layer;

	mark.rubberBand->reset();
	delete mark.rubberBand;

	m_lstMark.removeAt(g_index);

	m_canvas->setLayers(g_layers);
	m_canvas->refresh();
}

void QgsMapToolAddItem::slotShowScale(double scale)
{
	qDebug() << "scale = " << scale;
}

void QgsMapToolAddItem::slotZoomLastStatusChanged(bool)
{
	for (int i = 0; i < m_lstMark.size(); i++)
	{
		QgsPointXY xy = m_lstMark.at(i).geo.asPoint();

		const QgsMapToPixel *mtransform = m_canvas->getCoordinateTransform();

		//转换到屏幕坐标
		QgsPointXY offsetPoint = mtransform->transform(xy.x(), xy.y());

		int yOffset = 25;
		offsetPoint.setY(offsetPoint.y() + yOffset);

		//转回去到地图坐标
		offsetPoint = mtransform->toMapCoordinates(offsetPoint.x(), offsetPoint.y());

		m_lstMark.at(i).text->setPoint(QgsPoint(offsetPoint.x(), offsetPoint.y()));
	}
}

4.更多参考

Qgis二次开发-QgsAnnotationItem(添加文字、图片标注(支持svg、png、jpg等常用图片格式))_Mr.codeee的博客-CSDN博客

Qgis二次开发-QgsMapCanvas画布简介_Mr.codeee的博客-CSDN博客 

Qgis二次开发-QgsRubberBand详解(画线、画多边形)_Mr.codeee的博客-CSDN博客 

Qgis二次开发-QgsAnnotationItem(添加文字、图片标注(支持svg、png、jpg等常用图片格式))_Mr.codeee的博客-CSDN博客 文章来源地址https://www.toymoban.com/news/detail-599802.html

到了这里,关于Qgis二次开发-QgsMapTool地图交互工具详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QGIS二次开发四:实现图层列表

    在实际开发中我们通常会遇到同时显示多个图层,并且还要实时显示和隐藏各图层的需求,如同 ArcGIS 的图层列表那样,界面左侧显示图层列表,列出当前已加载的所有图层,同时每个图层前面有复选框可以控制图层的显示/隐藏;界面右侧为画布,按图层列表的适当顺序显示

    2024年02月13日
    浏览(34)
  • Ubuntu 22.04 配置 QGIS二次开发环境

    源码地址: https://github.com/qgis/QGIS/releases QGIS 官方指导文档地址: https://github.com/qgis/QGIS/blob/release-3_26/INSTALL.md(此处为3.26的指导文档,可以自行修改查看) sudo apt-get install bison ca-certificates ccache cmake cmake-curses-gui dh-python doxygen expect flex flip gdal-bin git graphviz grass-dev libexiv2-dev l

    2024年02月16日
    浏览(63)
  • QGIS3.28的二次开发一:编译工程

    更新:最近写了个3.18.3版本的编译教程,没有出现任何问题。 QGIS3.18编译教程_程序员班长的博客-CSDN博客 环境:VS2019+OSGeo4W+CMake_3.26+Cygwin64+QGIS_3.28 注意:一定要按照步骤顺序来! VS2019下载链接 https://my.visualstudio.com/Downloads?q=visual%20studio%202019wt.mc_id=o~msft~vscom~older-downloads 下载完

    2024年02月15日
    浏览(49)
  • QGIS二次开发:集成二维CAD控件MxDraw

    本文记录在QGIS中集成MxDraw控件的方法。 参见笔者博文“FreeCAD二次开发:集成二维CAD控件MxDraw”所述的安装方法。 参见笔者博文\\\"Windows 10下编译安装QGIS\\\"所述的编译安装方法。 按照QGIS的管理,Qt ui文件可放到src/ui目录及其子目录下。因此,可将MxDrawView.ui拷贝到src/ui/gd目录下,

    2024年02月15日
    浏览(37)
  • QGIS3.28的二次开发九:添加矢量要素

    对矢量要素的编辑是 GIS 软件很重要的功能点之一,也是最难实现的功能点之一。编辑矢量要素涉及到很多方面的考虑,包括且不限于矢量要素的几何类型,拓扑关系,构成要素的节点的增删改,编辑会话 (session) 的启动、回溯和提交,要素属性的增删改等。本文不会也不可能

    2024年02月12日
    浏览(47)
  • Qt下开发基于QGIS的应用程序

    由于有在背景地图上进行动态轨迹(曲线)显示的需要,故采用Qt+QGIS的方案! Qt5.12.12,VS2015编译器,QGIS3.10.1。 在配置之前,电脑是新装机的系统,没有任何相关软件版本。 在Qt官网(https://download.qt.io/)或国内镜像网站(https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt)或网络搜索

    2024年02月14日
    浏览(59)
  • C# Solidworks二次开发:程序工具界面和选项相关API详解

    大家好,今天要讲的是关于程序工具相关的API介绍。 下面是要介绍的API: (1)第一个为GetAutoPartSimplification,这个API的含义为获取简化配置的指针,下面是官方具体解释: 其输入参数的类型在上一篇文章中已经介绍过了gtError_e,返回值为指向简化配置的指针。 (2)第二个为Ge

    2024年04月17日
    浏览(51)
  • QGIS开发五:VS使用QT插件创建UI界面

    前面我们说了在创建项目时创建的是一个空项目,即不使用 Qt 提供的综合开发套件 Qt Creator,也不使用 Qt Visual Studio Tools 这类工具。 但是后面发现,如果我想要有更加满意的界面布局,还是要自己写一个UI文件,如果不使用QT插件,在VS中导入自己的UI文件编译起来不是那么容

    2024年02月13日
    浏览(59)
  • 【ArcGIS Pro二次开发】(57):地图系列

    在ArcGIS Pro中,有一个地图系列,可以在一个布局中导出多个地图。 在SDK中为ArcGIS.Desktop.layout.MapSeries类和映射系列导出选项,可以以支持多页导出。 MapSeries类提供了一个静态CreateSpatialMapSeries方法,该方法使用指定的索引层(作为参数传递)为给定布局生成空间地图系列。 使

    2024年02月14日
    浏览(47)
  • openlayers [六] 地图交互 interaction 详解

    地图的交互功能包含很多,如地图双击放大,鼠标滚轮缩放,矢量要素点选,地图上绘制图形等等。只要是涉及到与地图的交互,就会涉及到 intercation 类,它定义了用户与地图进行交互的基本要素和事件。 在 OpenLayers 6 中,表达交互功能的基类是 interaction,它是一个虚基类,

    2024年01月19日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包