地图交互动作就是通过鼠标操作与地图间的互动。动作包括按下(press)、按键弹起(release)、鼠标移动(move)、双击等等。
QGIS实现地图的交互主要是通过继承QgsMapTool这个类实现,目前集成了QgsMapToolZoom(拉框缩放)、QgsMapToolPan(地图移动)、QgsMapToolEmitPoint(点击地图)、QgsMapToolExtent(拉框)、QgsMapToolEdit(交互编辑)、QgsMapToolIdentify(点击矢量要素)。
这些个性动作主要是实现了QgsMapTool的几个接口:
virtual void | canvasDoubleClickEvent (QgsMapMouseEvent *e) |
双击鼠标 | |
virtual void | canvasMoveEvent (QgsMapMouseEvent *e) |
鼠标移动 | |
virtual void | canvasPressEvent (QgsMapMouseEvent *e) |
鼠标按下 | |
virtual void | canvasReleaseEvent (QgsMapMouseEvent *e) |
鼠标抬起 |
下面我们将通过一个封装类实现点击画点的交互动作
一、思路
动作逻辑:点击地图->获取点击处的坐标->绘制地图
实现:继承QgsMapToolEmitPint,实现canvasReleaseEvent即可,如下:
void SHQgsMapToolEmitPoint::canvasReleaseEvent(QgsMapMouseEvent *e){
QgsMapToolEmitPoint::canvasReleaseEvent(e);
if(!mMapCanvas)return;
QgsRubberBand *rb = new QgsRubberBand(mMapCanvas,QgsWkbTypes::PointGeometry);
rb->setSize(100);
rb->setColor(QColor(255,0,0));
rb->addPoint(e->mapPoint); //画点
}
二、进阶
如果我们现在有个新的需求,比如实现点击获取坐标,显然我们依照上面的思路通过再继承QgsMapToolEmitPoint也可以实现。但很明显“点击画点”和“点击获取坐标"的实现基本都差不多,区别仅仅在于最后一步的实现不同而已。能否再抽象,实现更佳的封装和调用呢。答案是明显了,思路:
1、定义不同的交互动作
2、设置动作
3、点击时发送信号传送坐标
4、在槽函数中根据动作不同对坐标进行不同处理,从而实现点击获取坐标和点击绘制
如下:
第一步:定义动作
enum MapAction{
Null, //无动作
PointClick, //点击
DrawPoint, //绘制点
};
Q_ENUM(MapAction);
第二步:setAction定义和实现,信号和槽函数关联
//mAction用来记录当前动作的成员变量
void MyTest::setAction(MapAction action){
if(action==MapAction::PointClick || action==MapAction::DrawPoint){
mAction = action;
if(!this->mEmitPointTool){
this->mEmitPointTool = new MyQgsMapToolEmitPoint(this->m_mapCanvas); connect(mEmitPointTool,SIGNAL(signal_point_click(QgsPointXY)),this,SLOT(handlePointClickEvent(QgsPointXY)));
}
this->m_mapCanvas->setMapTool(this->mEmitPointTool);
}else{
mAction = MapAction::Null;
QgsMapTool *tool = this->m_mapCanvas->mapTool();
this->m_mapCanvas->unsetMapTool(tool);
}
}
实现点击类,增加坐标的返回
//重载canvasReleaseEvent,实现信号signal_point_click的发送,传递回点击处坐标
void MyMapToolEmitPoint::canvasReleaseEvent(QgsMapMouseEvent *e){
QgsMapToolEmitPoint::canvasReleaseEvent(e);
if(!mMapCanvas)return;
emit signal_point_click(e->mapPoint);
}
第三步:实例化MyMapToolEmitPoint,并作为成员变量
//m_mapCanvas是地图画布指针
MyQgsMapToolEmitPoint mEmitPointTool = new MyQgsMapToolEmitPoint(this->m_mapCanvas);
第四步:槽函数实现
/**
* 处理点击事件
* @brief SHQgisMap2DHandler::handlePointClickEvent
* @param xy
*/
void SHQgisMap2DHandler::handlePointClickEvent(QgsPointXY xy){
if(m_action==SHMapAction::MapAction::PointClick) {
QString msg = QString("%1").arg(xy.x());
msg += QString(",%1").arg(xy.y());
QDebug<setSize(100);
rb->setColor(QColor(200,0,0));
rb->addPoint(xy);
}
}
第五步:调用
setAction(MapAction::DrawPoint);
设置点击画点动作,在地图上点击即可以绘制点对象。
三、再进阶
实现交互动作后的回调,如setAction(xxx,myCallBack);
思路:1、定义一个回调类,比如MyCallBack,里面有不同的实现的回调函数callback
2、在上面的槽函数里调用具体的回调函数callback即可
当然用信号和槽函数也可以实现类似。