研究过源码的人都知道 QGIS对于在地图上的功能操作都是通过QgsMapTool来管理的,有一篇博客有详细讲解:http://blog.youkuaiyun.com/deirjie/article/details/50878670
所以要实现画图也很简单了。
首先继承QgsMapTool,这里提供了各种坐标转换,我们当然非常需要。
#ifndef MEASURETOOL_H
#define MEASURETOOL_H
#include <qgsmaptool.h>
#include <QList>
class QgsDistanceArea;
class QgsMapCanvas;
class QgsRubberBand;
class MeasureTool : public QgsMapTool
{
Q_OBJECT
public:
MeasureTool( QgsMapCanvas* canvas, bool measureArea );
~MeasureTool();
//virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
//! returns whether measuring distance or area
bool measureArea() { return mMeasureArea; }
//! When we have added our last point, and not following
bool done() { return mDone; }
//! Reset and start new
void restart();
//! Add new point
void addPoint( const QgsPoint &point );
//! Returns reference to array of the points
const QList<QgsPoint>& points();
// Inherited from QgsMapTool
//! Mouse move event for overriding
virtual void canvasMoveEvent( QgsMapMouseEvent* e ) override;
//! Mouse press event for overriding
virtual void canvasPressEvent( QgsMapMouseEvent* e ) override;
//! Mouse release event for overriding
virtual void canvasReleaseEvent( QgsMapMouseEvent* e ) override;
//! called when set as currently active map tool
virtual void activate() override;
//! called when map tool is being deactivated
virtual void deactivate() override;
virtual void keyPressEvent( QKeyEvent* e ) override;
public slots:
//! updates the projections we're using
void updateSettings();
protected:
QList<QgsPoint> mPoints;
//! Rubberband widget tracking the lines being drawn
QgsRubberBand *mRubberBand;
//! Rubberband widget tracking the added nodes to line
QgsRubberBand *mRubberBandPoints;
//! indicates whether we're measuring distances or areas
bool mMeasureArea;
//! indicates whether we've just done a right mouse click
bool mDone;
//! indicates whether we've recently warned the user about having the wrong
// project projection
bool mWrongProjectProjection;
//! Destination CoordinateReferenceSystem used by the MapCanvas
QgsCoordinateReferenceSystem mDestinationCrs;
//! Returns the snapped (map) coordinate
//@param p (pixel) coordinate
QgsPoint snapPoint( const QPoint& p );
/** Removes the last vertex from mRubberBand*/
void undo();
};
#endif // MEASURETOOL_H
源文件:
#include "qgsdistancearea.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaptopixel.h"
#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
#include "qgssnappingutils.h"
#include "qgstolerance.h"
#include "qgscursors.h"
#include "qgsmessagelog.h"
#include "MeasureTool.h"
#include <QMessageBox>
#include <QMouseEvent>
#include <QSettings>
MeasureTool::MeasureTool( QgsMapCanvas* canvas, bool measureArea )
: QgsMapTool( canvas )
, mWrongProjectProjection( false )
{
mMeasureArea = measureArea;
mRubberBand = new QgsRubberBand( canvas, mMeasureArea ? QGis::Polygon : QGis::Line );
mRubberBand->setIcon(QgsRubberBand::ICON_FULL_BOX);
mRubberBandPoints = new QgsRubberBand( canvas, QGis::Point );
QPixmap myCrossHairQPixmap = QPixmap(( const char ** ) cross_hair_cursor );
mCursor = QCursor( myCrossHairQPixmap, 8, 8 );
mDone = true;
// Append point we will move
mPoints.append( QgsPoint( 0, 0 ) );
mDestinationCrs = canvas->mapSettings().destinationCrs();
// mDialog = new QgsMeasureDialog( this );
// mDialog->setWindowFlags( mDialog->windowFlags() | Qt::Tool );
// mDialog->restorePosition();
connect( canvas, SIGNAL( destinationCrsChanged() ),
this, SLOT( updateSettings() ) );
}
MeasureTool::~MeasureTool()
{
// delete mDialog;
delete mRubberBand;
delete mRubberBandPoints;
}
const QList<QgsPoint>& MeasureTool::points()
{
return mPoints;
}
void MeasureTool::activate()
{
// mDialog->show();
QgsMapTool::activate();
// ensure that we have correct settings
updateSettings();
// If we suspect that they have data that is projected, yet the
// map CRS is set to a geographic one, warn them.
if ( mCanvas->mapSettings().destinationCrs().geographicFlag() &&
( mCanvas->extent().height() > 360 ||
mCanvas->extent().width() > 720 ) )
{
QMessageBox::warning( nullptr, tr( "Incorrect measure results" ),
tr( "<p>This map is defined with a geographic coordinate system "
"(latitude/longitude) "
"but the map extents suggests that it is actually a projected "
"coordinate system (e.g., Mercator). "
"If so, the results from line or area measurements will be "
"incorrect.</p>"
"<p>To fix this, explicitly set an appropriate map coordinate "
"system using the <tt>Settings:Project Properties</tt> menu." ) );
mWrongProjectProjection = true;
}
}
void MeasureTool::deactivate()
{
// mDialog->hide();
QgsMapTool::deactivate();
}
void MeasureTool::restart()
{
mPoints.clear();
mRubberBand->reset( mMeasureArea ? QGis::Polygon : QGis::Line );
mRubberBandPoints->reset( QGis::Point );
mDone = true;
mWrongProjectProjection = false;
}
void MeasureTool::updateSettings()
{
QSettings settings;
int myRed = settings.value( "/qgis/default_measure_color_red", 222 ).toInt();
int myGreen = settings.value( "/qgis/default_measure_color_green", 155 ).toInt();
int myBlue = settings.value( "/qgis/default_measure_color_blue", 67 ).toInt();
mRubberBand->setColor( QColor( myRed, myGreen, myBlue, 100 ) );
mRubberBand->setWidth( 3 );
mRubberBandPoints->setIcon( QgsRubberBand::ICON_CIRCLE );
mRubberBandPoints->setIconSize( 10 );
mRubberBandPoints->setColor( QColor( myRed, myGreen, myBlue, 150 ) );
// Reproject the points to the new destination CoordinateReferenceSystem
if ( mRubberBand->size() > 0 && mDestinationCrs != mCanvas->mapSettings().destinationCrs() )
{
QList<QgsPoint> points = mPoints;
bool lastDone = mDone;
// mDialog->restart();
mDone = lastDone;
QgsCoordinateTransform ct( mDestinationCrs, mCanvas->mapSettings().destinationCrs() );
Q_FOREACH ( const QgsPoint& previousPoint, points )
{
try
{
QgsPoint point = ct.transform( previousPoint );
mPoints.append( point );
mRubberBand->addPoint( point, false );
mRubberBandPoints->addPoint( point, false );
}
catch ( QgsCsException &cse )
{
QgsMessageLog::logMessage( QString( "Transform error caught at the MeasureTool: %1" ).arg( cse.what() ) );
}
}
mRubberBand->updatePosition();
mRubberBand->update();
mRubberBandPoints->updatePosition();
mRubberBandPoints->update();
}
mDestinationCrs = mCanvas->mapSettings().destinationCrs();
//mDialog->updateSettings();
if ( !mDone && mRubberBand->size() > 0 )
{
mRubberBand->addPoint( mPoints.last() );
// mDialog->addPoint( mPoints.last() );
}
if ( mRubberBand->size() > 0 )
{
mRubberBand->setVisible( true );
mRubberBandPoints->setVisible( true );
}
}
//
void MeasureTool::canvasPressEvent( QgsMapMouseEvent* e )
{
Q_UNUSED( e );
}
void MeasureTool::canvasMoveEvent( QgsMapMouseEvent* e )
{
if ( ! mDone )
{
QgsPoint point = snapPoint( e->pos() );
mRubberBand->movePoint( point );
// mDialog->mouseMove( point );
}
}
void MeasureTool::canvasReleaseEvent( QgsMapMouseEvent* e )
{
QgsPoint point = snapPoint( e->pos() );
if ( mDone ) // if we have stopped measuring any mouse click restart measuring
{
//mDialog->restart();
}
if ( e->button() == Qt::RightButton ) // if we clicked the right button we stop measuring
{
mDone = true;
}
else if ( e->button() == Qt::LeftButton )
{
mDone = false;
}
// we always add the clicked point to the measuring feature
addPoint( point );
// mDialog->show();
}
void MeasureTool::undo()
{
if ( mRubberBand )
{
if ( mPoints.size() < 1 )
{
return;
}
if ( mPoints.size() == 1 )
{
//removing first point, so restart everything
restart();
// mDialog->restart();
}
else
{
//remove second last point from line band, and last point from points band
mRubberBand->removePoint( -2, true );
mRubberBandPoints->removePoint( -1, true );
mPoints.removeLast();
// mDialog->removeLastPoint();
}
}
}
void MeasureTool::keyPressEvent( QKeyEvent* e )
{
if (( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) )
{
if ( !mDone )
{
undo();
}
// Override default shortcut management in MapCanvas
e->ignore();
}
}
void MeasureTool::addPoint( const QgsPoint &point )
{
QgsDebugMsg( "point=" + point.toString() );
// don't add points with the same coordinates
if ( !mPoints.isEmpty() && mPoints.last() == point )
{
return;
}
QgsPoint pnt( point );
// Append point that we will be moving.
mPoints.append( pnt );
mRubberBand->addPoint( point );
mRubberBandPoints->addPoint( point );
if ( ! mDone ) // Prevent the insertion of a new item in segments measure table
{
//mDialog->addPoint( point );
}
}
QgsPoint MeasureTool::snapPoint( const QPoint& p )
{
QgsPointLocator::Match m = mCanvas->snappingUtils()->snapToMap( p );
return m.isValid() ? m.point() : mCanvas->getCoordinateTransform()->toMapCoordinates( p );
}
使用
线段:
MeasureTool* addFeatureTool = new MeasureTool( mapCanvas, false);
mapCanvas->setMapTool( addFeatureTool );面积:
MeasureTool* addFeatureTool = new MeasureTool( mapCanvas, true);
mapCanvas->setMapTool( addFeatureTool );