18

I want to know how to check for a mouse click in QGIS. I am trying to write a python plugin and want to provide functionality similar to the "Select Single Feature" tool that already exists in QGIS.

I checked the QGIS api docs and found

QgsMapCanvas::CanvasProperties::mouseButtonDown

This sounds promising. I have a QgsMapCanvas object but I can't see how to access the mouseButtonDown attribute.

I am completely new to the QGIS API.

22

The best way to make a new tool like the Select Single Feature tool is to inherit from the QgsMapTool class. When your tool is active, which can be set using QgsMapCanvas::setMapTool, any keyboard or click events the canvas gets will be passed onto your custom tool.

Here is a basic QgsMapTool class

class PointTool(QgsMapTool):   
    def __init__(self, canvas):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas    

    def canvasPressEvent(self, event):
        pass

    def canvasMoveEvent(self, event):
        x = event.pos().x()
        y = event.pos().y()

        point = self.canvas.getCoordinateTransform().toMapCoordinates(x, y)

    def canvasReleaseEvent(self, event):
        #Get the click
        x = event.pos().x()
        y = event.pos().y()

        point = self.canvas.getCoordinateTransform().toMapCoordinates(x, y)

    def activate(self):
        pass

    def deactivate(self):
        pass

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

You can do what you need in canvasReleaseEvent, etc

To set this tool active you just do:

tool = PointTool(qgis.iface.mapCanvas())
qgis.iface.mapCanvas().setMapTool(tool)
  • Thank you for your response. Its exactly what I need. However, when I try implementing this solution I get the following error: class PointTool(QgsMapTool): NameError: name 'QgsMapTool' is not defined. Any ideas? – robert Jan 3 '13 at 12:34
  • 1
    You will need to use from qgis.gui import QgsMapTool at the top – Nathan W Jan 3 '13 at 12:39
  • Last question... How do you then deactivate this tool? – robert Jan 3 '13 at 12:49
  • Set maptool to something else, or to None. I would save what the user had selected using QgsMapCanvas.mapTool() restoring it after you are done. – Nathan W Jan 3 '13 at 13:01
  • @NathanW "To set maptool to something else" also means that I click 'Pan Map' on the toolbar, right? – wannik Nov 22 '14 at 12:51
3

I think you can do this with a combination of using QGIS "canvasClicked" but also SIGNAL/SLOTS to deal with the response:

result = QObject.connect(self.clickTool, SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"), self.handleMouseDown)

Not tried but should give you some more information to start looking at. There is a tutorial here where someone is using this to build a very basic plugin.

  • 1
    They are using the built in QgsMapToolEmitPoint class which will give you the basic start for a tool. A good way to connect to signals in PyQt is using this syntax self.clickTool.canvasClicked.connect(self.handleMouseDown) – Nathan W Jan 3 '13 at 12:35
1

Try something like this (this is to select a point):

def run(self):
    self.pointEmitter = QgsMapToolEmitPoint(self.iface.mapCanvas())
    QObject.connect( self.pointEmitter, SIGNAL("canvasClicked(const QgsPoint, Qt::MouseButton)"), self.selectNow)
    self.iface.mapCanvas().setMapTool( self.pointEmitter )

def selectNow(self, point, button):
  #QMessageBox.information(None, "Clicked coords", " x: " + str(point.x()) + " Y: " + str(point.y()) )

  layer = self.iface.activeLayer()
  if not layer or layer.type() != QgsMapLayer.VectorLayer:
     QMessageBox.warning(None, "No!", "Select a vector layer")
     return

  width = self.iface.mapCanvas().mapUnitsPerPixel() * 2
  rect = QgsRectangle(point.x() - width,
                      point.y() - width,
                      point.x() + width,
                      point.y() + width)

  rect = self.iface.mapCanvas().mapRenderer().mapToLayerCoordinates(layer, rect)

  layer.select([], rect)
  feat = QgsFeature()

  ids = []
  while layer.nextFeature(feat):
    ids.append( feat.id() )

  layer.setSelectedFeatures( ids )
  • I would use the self.clickTool.canvasClicked.connect(self.handleMouseDown) syntax to connect to signals as it's much cleaner. – Nathan W Jan 4 '13 at 4:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.