13. Comunicarse con el usuario

Consejo

Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de pyqgis:

 1from qgis.core import (
 2    QgsMessageLog,
 3    QgsGeometry,
 4)
 5
 6from qgis.gui import (
 7    QgsMessageBar,
 8)
 9
10from qgis.PyQt.QtWidgets import (
11    QSizePolicy,
12    QPushButton,
13    QDialog,
14    QGridLayout,
15    QDialogButtonBox,
16)

Esta sección muestra algunos métodos y elementos que deberían utilizarse para comunicarse con el usuario, con el objetivo de mantener la consistencia en la Interfaz del Usuario.

13.1. Mostrando mensajes. La clase QgsMessageBar

Utilizar las bandejas de mensajes puede ser una mala idea desde el punto de vista de la experiencia de un usuario. Para mostrar una pequeña línea de información o mensajes de advertencia/error, la barrar de mensajes de QGIS suele ser una mejor opción.

Utilizar la referencia a la interfaz objeto de QGIS, puede mostrar un mensaje en la barra de mensajes con el siguiente código

from qgis.core import Qgis
iface.messageBar().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that", level=Qgis.Critical)
Messages(2): Error : I'm sorry Dave, I'm afraid I can't do that
../../_images/errorbar.png

Figura 13.10 Barra de Mensajes de QGIS

Se puede establecer una duración para mostrarlo en un tiempo limitado

iface.messageBar().pushMessage("Ooops", "The plugin is not working as it should", level=Qgis.Critical, duration=3)
Messages(2): Ooops : The plugin is not working as it should
../../_images/errorbar-timed.png

Figura 13.11 Barra de Mensajes de QGIS con temporizador

Los ejemplos anteriores muestran una barra de error, pero el parámetro level se puede usar para crear mensajes de advertencia o mensajes de información, utilizando la enumeración Qgis.MessageLevel. Puede usar hasta 4 niveles diferentes:

  1. Información

  2. Advertencia

  3. Critica

  4. Éxito

../../_images/infobar.png

Figura 13.12 Barra de Mensajes de QGIS (información)

Se puede añadir complementos a la barra de mensajes, como por ejemplo un botón para mostrar más información

1def showError():
2    pass
3
4widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
5button = QPushButton(widget)
6button.setText("Show Me")
7button.pressed.connect(showError)
8widget.layout().addWidget(button)
9iface.messageBar().pushWidget(widget, Qgis.Warning)
Messages(1): Missing Layers : Show Me
../../_images/bar-button.png

Figura 13.13 Barra de Mensajes de QGIS con un botón

Incluso puedes utilizar una barra de mensajes en tu propio cuadro de diálogo para no tener que mostrar la bandeja de mensajes o si no tiene sentido mostrarla en la pantalla principal de QGIS.

 1class MyDialog(QDialog):
 2    def __init__(self):
 3        QDialog.__init__(self)
 4        self.bar = QgsMessageBar()
 5        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
 6        self.setLayout(QGridLayout())
 7        self.layout().setContentsMargins(0, 0, 0, 0)
 8        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok)
 9        self.buttonbox.accepted.connect(self.run)
10        self.layout().addWidget(self.buttonbox, 0, 0, 2, 1)
11        self.layout().addWidget(self.bar, 0, 0, 1, 1)
12    def run(self):
13        self.bar.pushMessage("Hello", "World", level=Qgis.Info)
14
15myDlg = MyDialog()
16myDlg.show()
../../_images/dialog-with-bar.png

Figura 13.14 Barra de Mensajes de QGIS con un cuadro de diálogo personalizado

13.2. Mostrando el progreso

Las barras de progreso también pueden ponerse en la barra de Mensajes de QGIS, ya que, como hemos visto, admite complementos. Este es un ejemplo que puedes probar en la consola.

 1import time
 2from qgis.PyQt.QtWidgets import QProgressBar
 3from qgis.PyQt.QtCore import *
 4progressMessageBar = iface.messageBar().createMessage("Doing something boring...")
 5progress = QProgressBar()
 6progress.setMaximum(10)
 7progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
 8progressMessageBar.layout().addWidget(progress)
 9iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)
10
11for i in range(10):
12    time.sleep(1)
13    progress.setValue(i + 1)
14
15iface.messageBar().clearWidgets()
Messages(0): Doing something boring...

Además, puede usar el constructor en la barra de estado para comunicar progreso, como en el siguiente ejemplo:

 1vlayer = iface.activeLayer()
 2
 3count = vlayer.featureCount()
 4features = vlayer.getFeatures()
 5
 6for i, feature in enumerate(features):
 7    # do something time-consuming here
 8    print('.') # printing should give enough time to present the progress
 9
10    percent = i / float(count) * 100
11    # iface.mainWindow().statusBar().showMessage("Processed {} %".format(int(percent)))
12    iface.statusBarIface().showMessage("Processed {} %".format(int(percent)))
13
14iface.statusBarIface().clearMessage()

13.3. Registro

Hay tres tipos diferentes de registro disponible en QGIS para registrar y guardar toda la información sobre la ejecución de su código. Cada uno tiene una ubicación de salida específica. Por favor considere el uso de la forma correcta de registro para su propósito:

  • QgsMessageLog es para que los mensajes comuniquen problemas al usuario. La salida del QgsMessageLog es mostrada en el Panel de Mensajes de Registro.

  • El python construido en el módilo registro es para depuración en el nivel de la API Python QGIS (PyQGIS). Es recomendado para desarrolladores de script Python que necesitan depurar su código python, e.g. ids o geometría de objeto espacial

  • QgsLogger es para mensajes para depuración / desarrolladores internos QGIS (i.e. usted sospecha que algo es gatillado por algún código dañado). Los mensajes sólo están visibles con versiones desarrollador de QGIS.

Ejemplos para los diferentes tipos de registro son mostrados en las siguientes secciones abajo.

Advertencia

El uso de la declaración print Python no es segura en ningún código que sea multihilos y ralentiza extremadamente el algoritmo. Esto incluye funciones de expresión, representadores, capas de símbolo y algoritmos Procesos (entre otros). En estos casos usted siempre debería usar en vez el módulo python registro o clases seguras de hilo (QgsLogger o QgsMessageLog).

13.3.1. QgsMessageLog

# You can optionally pass a 'tag' and a 'level' parameters
QgsMessageLog.logMessage("Your plugin code has been executed correctly", 'MyPlugin', level=Qgis.Info)
QgsMessageLog.logMessage("Your plugin code might have some problems", level=Qgis.Warning)
QgsMessageLog.logMessage("Your plugin code has crashed!", level=Qgis.Critical)
MyPlugin(0): Your plugin code has been executed correctly
(1): Your plugin code might have some problems
(2): Your plugin code has crashed!

Nota

Puede ver la salida de la QgsMessageLog en el Panel de mensajes de registro

13.3.2. El python construído en el módulo de registro

1import logging
2formatter = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
3logfilename=r'c:\temp\example.log'
4logging.basicConfig(filename=logfilename, level=logging.DEBUG, format=formatter)
5logging.info("This logging info text goes into the file")
6logging.debug("This logging debug text goes into the file as well")

El método basicConfig configura la definición básica del registro. En el código de arriba el nombre de archivo, nivel de registro y el formato son definidos. El nombre de archivo se refiere a donde escribir el archivo de registro, el nivel de registro define qué niveles imprimir y el formato define el formato en el que cada mensaje es impreso.

2020-10-08 13:14:42,998 - root - INFO - This logging text goes into the file
2020-10-08 13:14:42,998 - root - DEBUG - This logging debug text goes into the file as well

Si quiere borrar el archivo de registro cada vez que ejecuta su script usted puede hacer algo como:

if os.path.isfile(logfilename):
    with open(logfilename, 'w') as file:
        pass

Mayores recursos sobre cómo usar la instalación de registro python están disponibles en:

Advertencia

Por favor tome nota que sin registrar a un archivo al definir el nombre de archivo, el registro podría darse en multihilos lo que ralentiza fuertemente la salida.