En un post anterior se adaptó un plugin, de QGIS 2 a QGIS 3, para desplegar ráster values como tooltip. En este post se va a adaptar ese comportamiento para desplegar los valores de todos los atributos y el área (en hectáreas) de capas vectoriales. El código completo se expone a continuación y se copió en el template.py; renombrado posteriormente como measure_area.py en la carpeta measurearea. Sin embargo, para que funcione adecuadamente se requieren otras modificaciones que se detallan más adelante.
""" /*************************************************************************** Test A QGIS plugin Plugin for testing things ------------------- begin : 2015-01-28 copyright : (C) 2015-2017 by German Carrillo, GeoTux email : gcarrillo@linuxmail.org ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ """ import os # Import the PyQt and QGIS libraries from qgis.core import QgsApplication, QgsRasterLayer, QgsRaster, QgsVectorLayer, Qgis, QgsGeometry, QgsWkbTypes from qgis.gui import QgsMapToolEmitPoint from PyQt5.QtCore import QObject, QTimer from PyQt5.QtWidgets import ( QMessageBox, QAction, QMenu, QActionGroup, QWidgetAction, QToolTip) from PyQt5.QtGui import ( QIcon ) class Test: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface self.tooltipRaster = TooltipAreaPolygonMapTool( self.iface ) def initGui(self): # Create action that will start plugin configuration self.action = QAction( QIcon( os.path.dirname(os.path.realpath(__file__)) + "/icon_default.png" ), "Measure Feature Areas", self.iface.mainWindow() ) # connect the action to the run method self.action.triggered.connect( self.run ) self.action.setCheckable( True ) self.iface.mapCanvas().mapToolSet.connect( self.mapToolWasSet ) # Add toolbar button to the Plugins toolbar self.iface.addToolBarIcon(self.action) # Add menu item to the Plugins menu self.iface.addPluginToMenu("&Tooltip for Raster Values", self.action) def unload(self): # Remove the plugin menu item and icon self.iface.removePluginMenu( "&Tooltip for Raster Values", self.action ) self.iface.removeToolBarIcon(self.action) # run method that performs all the real work def run(self, checked): if checked: self.iface.mapCanvas().setMapTool( self.tooltipRaster ) else: self.iface.mapCanvas().unsetMapTool( self.tooltipRaster ) def mapToolWasSet( self, newTool ): if type(newTool) != TooltipAreaPolygonMapTool: self.action.setChecked( False ) class TooltipAreaPolygonMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.timerMapTips = QTimer( self.canvas ) self.timerMapTips.timeout.connect(self.showMapTip) def canvasPressEvent(self, e): point = self.toMapCoordinates(self.canvas.mouseLastXY()) if self.canvas.underMouse(): rLayer = self.iface.activeLayer() if type(rLayer) is QgsVectorLayer: feats_ids = rLayer.fields().allAttributesList() names = [ rLayer.fields().field(id).name() for id in feats_ids ] feats = [ feat for feat in rLayer.getFeatures() ] point = self.toMapCoordinates(self.canvas.mouseLastXY()) text = "no layer features" if rLayer.geometryType() == QgsWkbTypes.PolygonGeometry: for feat in feats: if QgsGeometry.fromPointXY(point).within(feat.geometry()): text = ", ".join(['{}: {}'.format(names[i], r) for i, r in enumerate(feat.attributes()) if r is not None] ) break else: pass def canvasReleaseEvent(self, e): pass def canvasMoveEvent(self, e): if self.canvas.underMouse(): # Only if mouse is over the map QToolTip.hideText() self.timerMapTips.start( 700 ) # time in milliseconds def deactivate(self): self.timerMapTips.stop() def showMapTip( self ): self.timerMapTips.stop() if self.canvas.underMouse(): rLayer = self.iface.activeLayer() if type(rLayer) is QgsVectorLayer: feats_ids = rLayer.fields().allAttributesList() names = [ rLayer.fields().field(id).name() for id in feats_ids ] feats = [ feat for feat in rLayer.getFeatures() ] point = self.toMapCoordinates(self.canvas.mouseLastXY()) text = "no layer features" if rLayer.geometryType() == QgsWkbTypes.PolygonGeometry: for feat in feats: if QgsGeometry.fromPointXY(point).within(feat.geometry()): text = ", ".join(['{}: {}'.format(names[i], r) for i, r in enumerate(feat.attributes()) if r is not None] )+ '\narea: ' + str(feat.geometry().area()/10000) + ' ha' break try: QToolTip.showText( self.canvas.mapToGlobal( self.canvas.mouseLastXY() ), text, self.canvas ) except UnboundLocalError: pass
La carpeta measurearea se encuentra en la ruta de plugins de QGIS 3. El archivo measure_area.py, que tiene el código anterior, para que se procese de la manera esperada es necesaria la modificación siguiente en el __init__py.
. . . def classFactory(iface): # load Test class from file test.py from .measure_area import Test return Test(iface)
También necesitamos la modificación siguiente en el metadata.txt para que el nombre del plugin sea procesado como se espera. Una modificación similar también fue realizada en el código fuente (measure_area.py) al inicio del método 'initGui'.
; the next section is mandatory [general] name=Measure Areas plugin description=For Measure Features Areas . . .
Finalmente, se produce un icono personalizado 24x24 (con el mismo nombre) para identificarlo de manera precisa. La ejecución del plugin se observa en la imagen a continuación.
No hay comentarios:
Publicar un comentario