13. Comunicare con l’utente

Suggerimento

I frammenti di codice di questa pagina necessitano delle seguenti importazioni se sei è al di fuori della console 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)

Questa sezione mostra alcuni metodi ed elementi che dovrebbero essere usati per comunicare con l’utente, in modo da mantenere la consistenza nell’interfaccia utente.

13.1. Mostrare i messaggi. La classe QgsMessageBar

Utilizzare il box dei messaggi potrebbe essere una cattiva idea dal punto di vista dell’esperienza utente. Solitamente, per mostrare un messaggio di informazione o di errore/avvertimento, la barra dei messaggi di QGIS é l’opzione migliore.

Utilizzando il riferimento all’oggetto interfaccia di QGIS, puoi mostrare un messaggio nella barra dei messaggi utilizzando il seguente codice

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

Fig. 13.10 Barra dei messaggi di QGIS

Puoi impostare una durata per visualizzarlo per un tempo limitato

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

Fig. 13.11 Barra dei messaggi di QGIS con timer

Gli esempi precedenti mostrano una barra di errore, ma il parametro level può essere usato per creare messaggi di avviso o di informazione, usando l’enumerazione Qgis.MessageLevel. Puoi utilizzare fino a 4 livelli diversi:

  1. Info

  2. Warning

  3. Critical

  4. Success

../../_images/infobar.png

Fig. 13.12 Barra dei messaggi di QGIS (informazioni)

I widget possono essere aggiunti alla barra dei messaggi, ad esempio il pulsante per mostrare piú informazioni

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

Fig. 13.13 Barra dei messaggi di QGIS con un pulsante

É possibile usare una barra dei messaggi nella propria finestra di dialogo senza dover mostrare una finestra di messaggi, o nel caso in cui non abbia senso mostrarla nella finestra principale di 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

Fig. 13.14 Barra dei messaggi di QGIS in una finestra di dialogo personalizzata

13.2. Mostrare l’avanzamento

Le barre di avanzamento si possono mettere anche nella barra dei messaggi di QGIS, dato che, come abbiamo visto, accetta i widget. Di seguito un esempio che potrete provare nella console.

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

Inoltre, puoi utilizzare la barra di stato integrata per segnalare i progressi, come nell’esempio successivo:

 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. Logging

In QGIS sono disponibili tre diversi tipi di registrazione per registrare e salvare tutte le informazioni sull’esecuzione del tuo codice. Ognuno di essi ha una posizione di output specifica. Si consiglia di utilizzare il metodo di registrazione corretto per il tuo scopo:

  • QgsMessageLog è per i messaggi che comunicano i problemi all’utente. L’output di QgsMessageLog è mostrato nel pannello dei messaggi di log.

  • Il modulo logging integrato in Python serve per il debug a livello dell’API Python di QGIS (PyQGIS). È consigliato agli sviluppatori di script Python che hanno bisogno di eseguire il debug del loro codice Python, ad esempio degli id degli elementi o delle geometrie.

  • QgsLogger è per i messaggi per il debugging interno di QGIS e per gli sviluppatori (ad esempio, si sospetta che qualcosa sia stato attivato da un codice non funzionante). I messaggi sono visibili solo con le versioni per sviluppatori di QGIS.

Gli esempi dei diversi tipi di registrazione sono illustrati nelle sezioni seguenti.

Avvertimento

L’uso dell’istruzione ``print”” di Python non è sicuro in qualsiasi codice che possa essere multithread e rallenta enormemente l’algoritmo. Ciò include funzioni di espressione, visualizzazione, livelli di simboli e algoritmi di elaborazione (tra gli altri). In questi casi si dovrebbe sempre usare il modulo logging di python o classi thread safe (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

Puoi vedere l’output di QgsMessageLog nel Pannello Messaggi di Log.

13.3.2. Il modulo di logging integrato in python

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")

Il metodo basicConfig configura la configurazione di base del logging. Nel codice precedente vengono definiti il nome del file, il livello di registrazione e il formato. Il nome del file si riferisce a dove scrivere il file di log, il livello di log definisce i livelli di output e il formato definisce il formato di output di ciascun messaggio.

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

Se vuoi cancellare il file di log ogni volta che esegui lo script, puoi fare qualcosa di simile:

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

Ulteriori risorse su come utilizzare la funzione di registrazione in python sono disponibili all’indirizzo:

Avvertimento

Si noti che se non si esegue la registrazione su un file impostando un nome di file, la registrazione può essere multithread, il che rallenta notevolmente l’output.