0


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

1.简介

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

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:画布移动、放大、缩小

源码:

#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:鼠标点击画矩形。

自定义一个地图交互工具继承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:右键弹出菜单标注地点。

#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博客

标签: qt qgis QgsMapTool

本文转载自: https://blog.csdn.net/wzz953200463/article/details/131853285
版权归原作者 Mr.codeee 所有, 如有侵权,请联系我们删除。

“Qgis二次开发-QgsMapTool地图交互工具详解”的评论:

还没有评论