13. Communiceren met de gebruiker

Hint

De codesnippers op deze pagina hebben de volgende import nodig als u buiten de console van PyQGIS bent:

 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)

Dit gedeelte geeft enkele methoden en elementen weer die zouden moeten worden gebruikt om te communiceren met de gebruiker, om consistentie in de gebruikersinterface te behouden.

13.1. Berichten weergeven. De klasse QgsMessageBar

Het gebruiken van berichtenvakken kan een slecht idee zijn vanuit het gezichtspunt van de gebruiker. Voor het weergeven van een korte regel met informatie of een waarschuwing/foutberichten, is de QGIS berichtenbalk gewoonlijk een betere optie.

U kunt, met behulp van de verwijzing naar het interface-object van QGIS, een bericht weergeven in de berichtenbalk met de volgende code

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 QGIS berichtenbalk

U kunt een duur instellen om het voor een beperkte tijd weer te geven

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 QGIS berichtenbalk met timer

Het voorbeeld hierboven geeft een foutenbalk weer, maar de parameter level kan worden gebruikt om waarschuwingen of informatie-berichten te maken, respectievelijk met behulp van de enumeratie Qgis.MessageLevel. U kunt tot maximaal 4 verschillende niveaus gebruiken.

  1. Informatie

  2. Waarschuwing

  3. Kritisch

  4. Succes

../../_images/infobar.png

Fig. 13.12 QGIS berichtenbalk (info)

Widgets kunnen aan de berichtenbalk worden toegevoegd, zoals bijvoorbeeld een knop om meer informatie weer te geven

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 QGIS berichtenbalk met een knop

U kunt zelfs een berichtenbalk in uw eigen dialoogvenster gebruiken zodat u geen berichtenvak hoeft weer te geven, of als het geen zin heeft om het in het hoofdvenster van QGIS weer te geven

 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 QGIS berichtenbalk in aangepast dialoogvenster

13.2. Voortgang weergeven

Voortgangsbalken kunnen ook worden opgenomen in de berichtenbalk van QGIS, omdat, zoals we al hebben gezien, die widgets accepteert. Hier is een voorbeeld dat u kunt proberen in de 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...

U kunt ook de ingebouwde statusbalk gebruiken om de voortgang weer te geven, zoals in het volgende voorbeeld:

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

Er zijn in QGIS drie verschillende soorten loggen beschikbaar om alle informatie over het uitvoeren van uw code te loggen en op te slaan. Elk heeft zijn eigen specifieke locatie voor de uitvoer. Bepaal eerst de juiste manier van loggen voor uw doel:

  • QgsMessageLog is voor het communiceren met gebruikers van problemen. De uitvoer van het QgsMessageLog wordt weergegeven in het paneel Logboekberichten.

  • De ingebouwde module van Python voor logging is voor het debuggen op het niveau van de QGIS Python API (PyQGIS). Het wordt aanbevolen aan scriptontwikkelaars in Python die hun code voor Python moeten debuggen, bijv. object-ID’s of geometrieën

  • QgsLogger is voor berichten voor QGIS intern debuggen / ontwikkelaars d.i. als u vermoedt dat zij worden veroorzaakt door een beschadigde code). Berichten zijn alleen zichtbaar in ontwikkelversies van QGIS.

Voorbeelden voor de verschillende typen van loggen worden weergegeven in de volgende gedeelten hieronder.

Waarschuwing

Gebruiken van het argument print in Python is niet veilig om in enige code te gebruiken die multithreaded zou kunnen zijn en vertraagt het algoritme extreem. Dit omvat functies voor expressies, renderers, symboollagen en algoritmes voor Processing (naast andere). In deze gevallen zou u in plaats daarvan altijd de module van Python logging of thread-veilige klassen (QgsLogger of QgsMessageLog) moeten gebruiken.

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!

Notitie

U kunt de uitvoer van QgsMessageLog zien in het Paneel Logboekmeldingen

13.3.2. De ingebouwde module voor loggen 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")

De methode basicConfig configureert de basis instelling van het loggen. In de bovenstaande code worden de bestandsnaam, het niveau van loggen en de indeling gedefinieerd. De bestandsnaam verwijst naar waar het logbestand moet worden weggeschreven, het niveau van loggen definieert welke niveaus moeten worden uitgevoerd en de indeling definieert de indeling waarin elk bericht wordt uitgevoerd.

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

Als u het logbestand wilt verwijderen, elke keer als u uw script uitvoert, kunt u iets doen als:

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

Meer bronnen over hoe de mogelijkheden voor loggen in Python te gebruiken zijn beschikbaar op:

Waarschuwing

Onthoud dat loggen zonder dat naar en bestand te sturen door een bestandsnaam in te stellen het loggen multithreaded zou kunnen zijn, wat de uitvoer in hoge mate vertraagt.