Die TopDeutschland des Bundesamts für Kartographie und Geodäsie (BKG) ist ein für den mobilen Einsatz aufbereitetes QGIS, welches u.a. im Krisenfall verwendet werden kann. Sie enthält deutschlandweite, mitunter sehr große Geobasisdaten für den Offline-Zugriff.
Die WhereGroup hat im Rahmen dieses Projekts ein PyQGIS-Plugin entwickelt, welches über die BKG-Webdienste eine Komplett- und Teilaktualisierung der einzelnen Datensätze ermöglicht.
Bei der Entwicklung des Plugins hatten wir anfänglich die Herausforderung, dass QGIS immer wieder eingefroren ist, wenn das Plugin eine Funktion zum Download großer Daten oder eine andere umfangreiche Verarbeitung aufgerufen hat.
In solchen Fällen ist die Hintergrundverarbeitung mit QGIS-Tasks (QgsTask) eine bequeme Möglichkeit, eine reaktionsschnelle Benutzeroberfläche beizubehalten.
QgsTask ist gewissermaßen ein Container für den im Hintergrund auszuführenden Code. Es können mehrere Tasks gleichzeitig ausgeführt werden. Normalerweise wird der globale Task-Manager (QgsApplication.taskManager()) verwendet, um die Ausführung der einzelnen Tasks zu steuern.
Ein QGIS-Task darf niemals GUI-basierte Vorgänge ausführen, beispielsweise das Erstellen neuer Widgets oder die Interaktion mit vorhandenen Widgets. Auf Qt-Widgets darf nur vom Hauptthread aus zugegriffen oder diese geändert werden. Ansonsten kommt es zu Abstürzen von QGIS.
Grundsätzlich gibt es drei Möglichkeiten, einen QGIS-Task zu erstellen:
Aus einer Funktion
Durch Erweiterung der QgsTask-Klasse
Aus einem Processing-Algorithmus
Nachfolgend werden Code-Auszüge aus dem vorangehend erwähnten Plugin zur Datenaktualisierung am Beispiel des zu aktualisierenden Vektorlayers „Geographische Namen“ gezeigt, in welchem ein QGIS-Task aus einer Funktion verwendet wird (d.h. Möglichkeit 1).
Die anderen beiden Möglichkeiten zur Erstellung eines QGIS-Tasks werden im PyQGIS Developer Cookbook näher beschrieben.
Für unseren Task verwenden wir zum einen diese Funktion:
def run_update_gn_task(self, task, dirname, overwrite):
QgsMessageLog.logMessage(...)
task.setProgress(0)
update_gn_task(task, dirname, overwrite)
if task.isCanceled():
self.stopped(task)
return None
task.setProgress(100)
return {'task': task.description()}
Zwei weitere Funktionen benötigen wir noch, um einen Task vollständig definieren zu können:
def stopped(self, task):
QgsMessageLog.logMessage(...)
def completed(self, exception, result=None):
if exception is None:
if result is None:
QgsMessageLog.logMessage(...)
else:
QgsMessageLog.logMessage(...)
else:
QgsMessageLog.logMessage(...)
raise exception
Mit QgsTask.fromFunction können wir die Task-Funktion und die completed-Funktion nun zu einem QgsTask umwandeln:
def run(self):
...
self.task = QgsTask.fromFunction("Aktualisierung von Geographische Namen",
self.run_update_gn_task, on_finished=self.completed, dirname=dirname,
overwrite=overwrite, flags=QgsTask.CanCancel)
QgsApplication.taskManager().addTask(self.task)
Sobald ein Task erstellt wurde, kann er mit der Funktion addTask() des Task-Managers zur Ausführung geplant werden.
Das „Eigentum“ am Task wird durch das Hinzufügen zum Task-Manager an letzteren übertragen. Der Task-Manager ist dann für den Start des Tasks verantwortlich. Außerdem bereinigt und löscht er Tasks, nachdem sie ausgeführt wurden.
Der Status von Tasks kann mithilfe von verschiedenen Signalen und Funktionen überwacht werden.
Wenn Sie große Datensätze herunterladen oder umfangreiche Prozesse durchführen möchten – wie dies im Falle unseres Plugins der Fall war – sind QGIS-Tasks eine gute Möglichkeit, eine reaktionsschnelle Benutzeroberfläche beizubehalten. Unbedingt zu beachten ist allerdings, dass man in einem QGIS-Task keinesfalls GUI-basierte Vorgänge ausführen darf, da es sonst zu unerwarteten Abstürzen von QGIS kommt – welche ich mir anfangs, zugegebenermaßen nicht richtig erklären konnte. Dies hat bei mir zwar ein gewisses Umdenken in der Plugin-Programmierung erfordert, aber schließlich ermöglichen mir QGIS-Tasks, große Datensätze herunterzuladen und währenddessen trotzdem normal in QGIS weiterzuarbeiten.
Weitere Beiträge, die Dich interessieren könnten: