25

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.

3 Answers 3

25

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)
7
  • 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
    Commented Jan 3, 2013 at 12:34
  • 1
    You will need to use from qgis.gui import QgsMapTool at the top
    – Nathan W
    Commented Jan 3, 2013 at 12:39
  • Last question... How do you then deactivate this tool?
    – robert
    Commented Jan 3, 2013 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
    Commented Jan 3, 2013 at 13:01
  • @NathanW "To set maptool to something else" also means that I click 'Pan Map' on the toolbar, right?
    – wannik
    Commented Nov 22, 2014 at 12:51
5

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
  • 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
    Commented Jan 3, 2013 at 12:35
2

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 )
1
  • I would use the self.clickTool.canvasClicked.connect(self.handleMouseDown) syntax to connect to signals as it's much cleaner.
    – Nathan W
    Commented Jan 4, 2013 at 4:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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