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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from qgis.core import (
    QgsMessageLog,
    QgsGeometry,
)

from qgis.gui import (
    QgsMessageBar,
)

from qgis.PyQt.QtWidgets import (
    QSizePolicy,
    QPushButton,
    QDialog,
    QGridLayout,
    QDialogButtonBox,
)

13. Comunicarse con el usuario

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.23 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.24 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.25 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

1
2
3
4
5
6
7
8
9
def showError():
    pass

widget = iface.messageBar().createMessage("Missing Layers", "Show Me")
button = QPushButton(widget)
button.setText("Show Me")
button.pressed.connect(showError)
widget.layout().addWidget(button)
iface.messageBar().pushWidget(widget, Qgis.Warning)
Messages(1): Missing Layers : Show Me
../../_images/bar-button.png

Figura 13.26 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.

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

myDlg = MyDialog()
myDlg.show()
../../_images/dialog-with-bar.png

Figura 13.27 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.

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

for i in range(10):
    time.sleep(1)
    progress.setValue(i + 1)

iface.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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
vlayer = iface.activeLayer()

count = vlayer.featureCount()
features = vlayer.getFeatures()

for i, feature in enumerate(features):
    # do something time-consuming here
    print('.') # printing should give enough time to present the progress

    percent = i / float(count) * 100
    # iface.mainWindow().statusBar().showMessage("Processed {} %".format(int(percent)))
    iface.statusBarIface().showMessage("Processed {} %".format(int(percent)))

iface.statusBarIface().clearMessage()

13.3. Registro

There are three different types of logging available in QGIS to log and save all the information about the execution of your code. Each has its specific output location. Please consider to use the correct way of logging for your purpose:

  • QgsMessageLog is for messages to communicate issues to the user. The output of the QgsMessageLog is shown in the Log Messages Panel.

  • The python built in logging module is for debugging on the level of the QGIS Python API (PyQGIS). It is recommended for Python script developers that need to debug their python code, e.g. feature ids or geometries

  • QgsLogger is for messages for QGIS internal debugging / developers (i.e. you suspect something is triggered by some broken code). Messages are only visible with developer versions of QGIS.

Examples for the different logging types are shown in the following sections below.

Advertencia

Use of the Python print statement is unsafe to do in any code which may be multithreaded and extremely slows down the algorithm. This includes expression functions, renderers, symbol layers and Processing algorithms (amongst others). In these cases you should always use the python logging module or thread safe classes (QgsLogger or QgsMessageLog) instead.

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. The python built in logging module

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

The basicConfig method configures the basic setup of the logging. In the above code the filename, logging level and the format are defined. The filename refers to where to write the logfile to, the logging level defines what levels to output and the format defines the format in which each message is output.

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

If you want to erase the log file every time you execute your script you can do something like:

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

Further resources on how to use the python logging facility are available at:

Advertencia

Please note that without logging to a file by setting a filename the logging may be multithreaded which heavily slows down the output.