In this recipe, we will build a custom tool that both draws a shape on the map and interacts with other features on the map. These two basic functions are the basis for almost any map tool you would want to build, either in a standalone QGIS application like this one, or by extending the QGIS desktop application with a plugin.
We will use the application framework from the Adding standard map tools to the canvas recipe, so complete that recipe first. We will extend that application with a new tool. The complete version of this application is available in the code samples provided with this book. It will also be beneficial to study the other two tool-related recipes, A map tool to draw polygons or lines on the canvas and A map tool to draw points on the canvas, as this recipe builds on them as well.
You will also need the following zipped shapefile from https://geospatialpython.googlecode.com/files/NYC_MUSEUMS_GEO.zip.
Download and extract it to your qgis_data
directory.
We will add a new tool to the toolbar and also create a class describing our selection tool, including how to draw the selection polygon and how to select the features. To do this, we need to perform the following steps:
QAction("Pan")
method:actionSelect = QAction("Select", self)
actionSelect.setCheckable(True)
self.connect(actionSelect, SIGNAL("triggered()"), self.select)
self.toolbar.addAction(actionSelect)
self.toolSelect = SelectMapTool(self.canvas, self.lyr) self.toolSelect.setAction(actionSelect)
self.select()
def select(self): self.canvas.setMapTool(self.toolSelect)
canvasPressEvent
method, which receives the button click-event and the selectPoly
method. We will inherit from a generic tool to create points called the QgsMapToolEmitPoint
; we will also use an object called QgsRubberBand
to handle polygons. However, we must also perform the selection process to highlight the features that fall within our selection polygon:classSelectMapTool(QgsMapToolEmitPoint): def __init__(self, canvas, lyr): self.canvas = canvas self.lyr = lyr QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubberband = QgsRubberBand(self.canvas, QGis.Polygon) self.rubberband.setColor(QColor(255,255,0,50)) self.rubberband.setWidth(1) self.point = None self.points = [] defcanvasPressEvent(self, e): self.point = self.toMapCoordinates(e.pos()) m = QgsVertexMarker(self.canvas) m.setCenter(self.point) m.setColor(QColor(0,255,0)) m.setIconSize(5) m.setIconType(QgsVertexMarker.ICON_BOX) m.setPenWidth(3) self.points.append(self.point) self.isEmittingPoint = True self.selectPoly() defselectPoly(self): self.rubberband.reset(QGis.Polygon) for point in self.points[:-1]: self.rubberband.addPoint(point, False) self.rubberband.addPoint(self.points[-1], True) self.rubberband.show() iflen(self.points) > 2: g = self.rubberband.asGeometry() featsPnt = self.lyr.getFeatures(QgsFeatureRequest().setFilterRect(g.boundingBox())) forfeatPnt in featsPnt: iffeatPnt.geometry().within(g): self.lyr.select(featPnt.id())
QGIS has a generic tool for highlighting features, but in this case, we can use the standard selection functionality, which simplifies our code. With the exception of a dialog to load new layers and the ability to show attributes, we have a very basic but nearly complete standalone GIS application.The following screenshot shows the selection tool in action: