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? Commented Jan 3, 2013 at 12:34
  • 1
    You will need to use from qgis.gui import QgsMapTool at the top Commented Jan 3, 2013 at 12:39
  • Last question... How do you then deactivate this tool? 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. 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? 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) 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. Commented Jan 4, 2013 at 4:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.