Programaticamente verificar o clique do mouse no PyQGIS?

19

Quero saber como procurar um clique do mouse no QGIS. Estou tentando escrever um plug-in python e quero fornecer uma funcionalidade semelhante à ferramenta "Selecionar recurso único" que já existe no QGIS.

Eu verifiquei os documentos da API do QGIS e encontrei

QgsMapCanvas::CanvasProperties::mouseButtonDown

Isso parece promissor. Eu tenho um objeto QgsMapCanvas, mas não consigo ver como acessar o atributo mouseButtonDown.

Eu sou completamente novo na API QGIS.

Robert
fonte

Respostas:

23

A melhor maneira de criar uma nova ferramenta como a ferramenta Selecionar recurso único é herdar da QgsMapToolclasse. Quando sua ferramenta estiver ativa, que pode ser definida usando QgsMapCanvas::setMapTool, qualquer evento de teclado ou clique que a tela obtiver será passado para sua ferramenta personalizada.

Aqui está uma QgsMapToolclasse básica

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

Você pode fazer o que precisa canvasReleaseEvent, etc

Para ativar esta ferramenta, basta:

tool = PointTool(qgis.iface.mapCanvas())
qgis.iface.mapCanvas().setMapTool(tool)
Nathan W
fonte
Obrigado pela sua resposta. É exatamente o que eu preciso. No entanto, quando eu tentar implementar esta solução eu recebo o seguinte erro: class PointTool(QgsMapTool): NameError: name 'QgsMapTool' is not defined. Alguma ideia?
22613 Robert
1
Você precisará usar from qgis.gui import QgsMapToolno topo
Nathan W
Última pergunta ... Como você desativa esta ferramenta?
22613 Robert
Defina maptool para outra coisa ou para None. Eu salvaria o que o usuário selecionou usando a QgsMapCanvas.mapTool()restauração depois que você terminar.
Nathan W
@NathanW "Para definir maptool para outra coisa" também significa que eu clico em 'Pan Map' na barra de ferramentas, certo?
Wannik
3

Eu acho que você pode fazer isso com uma combinação do QGIS "canvasClicked", mas também SIGNAL / SLOTS para lidar com a resposta:

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

Não tentei, mas deve fornecer mais informações para você começar a olhar. Há um tutorial aqui onde alguém está usando isso para criar um plugin muito básico.

Dan
fonte
1
Eles estão usando a QgsMapToolEmitPointclasse incorporada, que fornecerá o começo básico de uma ferramenta. Uma boa maneira de se conectar aos sinais em PyQt está usando esta sintaxeself.clickTool.canvasClicked.connect(self.handleMouseDown)
Nathan W
1

Tente algo assim (isto é para selecionar um ponto):

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 )
André Barriguinha
fonte
Eu usaria a self.clickTool.canvasClicked.connect(self.handleMouseDown)sintaxe para conectar aos sinais, pois é muito mais limpo.
Nathan W