1

Below code can be use to get the X,Y Coordinate of clicked location .

class PrintSnappedPoint(QgsMapToolEmitPoint):
 def __init__(self, canvas):
 self.canvas = canvas
 QgsMapToolEmitPoint.__init__(self, self.canvas)
 self.l = iface.activeLayer()
 self.i = QgsSnapIndicator(self.canvas)
 self.u = self.canvas.snappingUtils()
 self.c = self.u.config()
 self.c.setEnabled(True)
 self.c.setMode(QgsSnappingConfig.AdvancedConfiguration)
 self.s = QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)
 def canvasMoveEvent(self, e):
 m = self.u.snapToMap(e.pos())
 self.i.setMatch(m)
 
 def canvasPressEvent(self, e):
 print("not called")
 transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:3111"),
 QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance())
 if self.i.match().type():
 pointxy = self.i.match().point()
 else:
 pointxy = None
 if pointxy:
 point = [pointxy.x(), pointxy.y()]
 print('Point snapped to vertex: {}'.format(point))
 
 def deactivate(self):
 self.s = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex , 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)
canvas = iface.mapCanvas()
T = PrintSnappedPoint(canvas)
canvas.setMapTool(T)

I wanted to implement same code with bottom click in QGIS plugin and want to get X, Y location and add them into two line edits X Coordinate and Y Coordinate.

I added below code to run method but the canvasMoveEvent function is not being called and does not affect any thing in map canvas.

def run(self):
 """Run method that performs all the real work"""
 # Create the dialog with elements (after translation) and keep reference
 # Only create GUI ONCE in callback, so that it will only load when the plugin is started
 if self.first_start == True:
 self.first_start = False
 self.dlg = ChidoByougaDialog()
 #conneting to function
 
 self.dlg.pushButton_2.clicked.connect(self.get_wakaban_coords)
 # show the dialog
 self.dlg.show()
 self.dlg.exec_()
 def get_wakaban_coords(self):
 canvas = self.iface.mapCanvas()
 T = PrintSnappedPoint(canvas,self.iface)
 canvas.setMapTool(T)
class PrintSnappedPoint(QgsMapToolEmitPoint):
 def __init__(self, canvas,iface):
 self.iface = iface
 self.canvas = canvas
 QgsMapToolEmitPoint.__init__(self, self.canvas)
 print("come upto here")
 self.l = self.iface.activeLayer()
 self.i = QgsSnapIndicator(self.canvas)
 self.u = self.canvas.snappingUtils()
 self.c = self.u.config()
 self.c.setEnabled(True)
 self.c.setMode(QgsSnappingConfig.AdvancedConfiguration)
 self.s = QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)
 print("lower end")
 def canvasMoveEvent(self, e):
 print("come to mouse event")
 m = self.u.snapToMap(e.pos())
 self.i.setMatch(m)
 print("not here")
 def canvasPressEvent(self, e):
 print("not called")
 transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:3111"),
 QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance())
 if self.i.match().type():
 pointxy = self.i.match().point()
 else:
 pointxy = None
 if pointxy:
 point = [pointxy.x(), pointxy.y()]
 print('Point snapped to vertex: {}'.format(point))
 def deactivate(self):
 self.s = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex, 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)

Is there any proper way to get location clicked by user and store in the Line Edit?

Kadir Şahbaz
78.6k57 gold badges260 silver badges407 bronze badges
asked Sep 15, 2021 at 2:10
3
  • 1
    I am not in front of a computer right now to test but I would suggest: 1. Create references to iface and canvas objects as instance attributes in the __init__() method of your plugin class e.g. self.iface = iface and self.canvas = self.iface.mapCanvas(). 2. Also create the instance of the map tool class in the __init__() method e.g. self.T = printSnappedPoint(self.canvas, self.iface). Then in the method get_wakaban_points() just do: self.canvas.setMapTool(self.T). I will try to post an answer later. Commented Sep 15, 2021 at 2:36
  • @Ben thank you so much it worked perfectly. Just curious to know how to add those return X,Y into line Edit of UI dynamically. Commented Sep 15, 2021 at 3:00
  • @Devenpali, no problem! I will try to make an answer later. The approach I would try is add a parent argument to the map tool class constructor, create a class attribute (self.parent = parent) and pass your plugin dialog (self.dlg) as the parent. You can then access the dialog widgets from inside the map tool class e.g. self.parent.line_edit.setText(str(point)) to replace the print statement. Commented Sep 15, 2021 at 8:34

1 Answer 1

2

Below is a complete, minimal, working plugin script which shows how to do what you what. I saved this file as __init__.py, placed it in a folder with an appropriate metadata.txt file and copied the folder into the QGIS plugins directory.

Note that to populate the line edit in the plugin dialog with the coordinates from mouse clicks on the map canvas, we need to add a parent argument to the map tool class constructor. Then when we instantiate the map tool class we pass in the plugin dialog (self.dlg) as the parent object. This allows us to access the dialog widgets from within the map tool class and use methods such as setText() when overriding the canvasPressEvent() method.

#-----------------------------------------------------------
# Copyright (C) 2021 Ben Wirf
#-----------------------------------------------------------
# Licensed under the terms of GNU GPL 2
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#---------------------------------------------------------------------
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QAction, QDialog, QLabel, QLineEdit, QPushButton,
 QGridLayout)
from qgis.core import QgsProject, QgsTolerance, QgsSnappingConfig, QgsCoordinateTransform
from qgis.gui import QgsMapToolEmitPoint, QgsSnapIndicator
def classFactory(iface):
 return GetSnappedMapPoint(iface)
class GetSnappedMapPoint:
 def __init__(self, iface):
 self.iface = iface
 self.dlg = MyDialog(self.iface)
 self.T = None
 def initGui(self):
 self.action = QAction('Launch', self.iface.mainWindow())
 self.action.triggered.connect(self.run)
 self.iface.addToolBarIcon(self.action)
 
 self.dlg.btn.clicked.connect(self.get_wakaban_coords)
 def unload(self):
 self.iface.removeToolBarIcon(self.action)
 del self.action
 def run(self):
 self.dlg.show()
 
 def get_wakaban_coords(self):
 self.T = PrintSnappedPoint(self.iface, self.dlg)
 self.iface.mapCanvas().setMapTool(self.T)
 
class MyDialog(QDialog):
 
 def __init__(self, iface):
 self.iface = iface
 QDialog.__init__(self)
 self.setGeometry(200, 200, 600, 200)
 self.lbl = QLabel('Point snapped to vertex:', self)
 self.line_edit = QLineEdit(self)
 self.btn = QPushButton('Set map tool', self)
 self.layout = QGridLayout()
 self.layout.addWidget(self.lbl, 0, 0, 1, 1, Qt.AlignCenter)
 self.layout.addWidget(self.line_edit, 0, 1, 1, 2)
 self.layout.addWidget(self.btn, 1, 1, 1, 1)
 self.setLayout(self.layout)
 
 self.setWindowFlags(Qt.WindowStaysOnTopHint)
 
 def closeEvent(self, e):
 self.line_edit.clear()
 self.iface.actionPan().trigger()
class PrintSnappedPoint(QgsMapToolEmitPoint):
 def __init__(self, iface, parent):
 #Note constructor takes a parent argument, a reference to
 #which is stored as self.parent
 self.iface = iface
 self.parent = parent
 self.canvas = self.iface.mapCanvas()
 QgsMapToolEmitPoint.__init__(self, self.canvas)
 self.l = self.iface.activeLayer()
 self.i = QgsSnapIndicator(self.canvas)
 self.u = self.canvas.snappingUtils()
 self.c = self.u.config()
 self.c.setEnabled(True)
 self.c.setMode(QgsSnappingConfig.AdvancedConfiguration)
 self.s = QgsSnappingConfig.IndividualLayerSettings(True, QgsSnappingConfig.Vertex, 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)
 def canvasMoveEvent(self, e):
 m = self.u.snapToMap(e.pos())
 self.i.setMatch(m)
 def canvasPressEvent(self, e):
 if self.i.match().type():
 pointxy = self.i.match().point()
 else:
 pointxy = None
 if pointxy:
 if self.l.crs() != QgsProject.instance().crs():
 x_form = QgsCoordinateTransform(QgsProject.instance().crs(),
 self.l.crs(),
 QgsProject.instance())
 tr = x_form.transform(pointxy)
 point = [tr.x(), tr.y()]
 else:
 point = [pointxy.x(), pointxy.y()]
 #Here we can access widgets in the plugin dialog
 #using the self.parent reference
 self.parent.line_edit.clear()
 self.parent.line_edit.setText('{}'.format(point))
 def deactivate(self):
 self.s = QgsSnappingConfig.IndividualLayerSettings(False, QgsSnappingConfig.Vertex, 25.00,
 QgsTolerance.Pixels)
 self.c.setIndividualLayerSettings(self.l, self.s)
 self.u.setConfig(self.c)

You can see how it works in the short screencast below:

enter image description here

You can find a minimal QGIS plugin template in this very useful resource from Martin Dobias here:

https://github.com/wonder-sk/qgis-minimal-plugin

answered Sep 16, 2021 at 1:07
1
  • @Devenepali, you're welcome :-) Commented Sep 23, 2021 at 6:57

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.