Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

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 so any and all help is greatly appreciated.

Thank you in advance.

share|improve this question

3 Answers 3

up vote 9 down vote accepted

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)
share|improve this answer
    
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
    
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

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.

share|improve this answer
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

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 )
share|improve this answer
    
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

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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