From 08b39f81d8fcb041a8b022fe237dd3f4f76e2318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Sat, 27 Sep 2025 12:54:39 +0200 Subject: [PATCH] Labels funktional --- pegelonline_dockwidget_base.ui | 98 +++++--- po_runner.py | 435 +++++++++++++++++++-------------- pomodules/pocurrentw.py | 2 + pomodules/poqgscurrentw.py | 6 + 4 files changed, 324 insertions(+), 217 deletions(-) diff --git a/pegelonline_dockwidget_base.ui b/pegelonline_dockwidget_base.ui index 0874d79..36dc7e0 100644 --- a/pegelonline_dockwidget_base.ui +++ b/pegelonline_dockwidget_base.ui @@ -6,8 +6,8 @@ 0 0 - 297 - 556 + 290 + 532 @@ -41,39 +41,65 @@ - - - Name - - - - - - - Zeitstempel - - - - - - - Aktueller Wert - - - - - - - mittelere niedrigste, höchste Pegel - - - - - - - absolute niedrigste, höchste Pegel - - + + + + + + + Name + + + + + + + Nummer + + + + + + + Organisation + + + + + + + Zeitstempel + + + + + + + + + + + Aktueller Wert + + + + + + + MNW, MHW + + + + + + + NSW, HSW + + + + + + @@ -119,7 +145,7 @@ - Unternehmen + Organisation diff --git a/po_runner.py b/po_runner.py index a5f575f..e5192a4 100644 --- a/po_runner.py +++ b/po_runner.py @@ -1,12 +1,14 @@ import os.path from typing import Callable -from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer +from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer, QgsPalLayerSettings, QgsVectorLayerSimpleLabeling from .pegelonline_dockwidget import PegelonlineDockWidget from .pomodules.poqgscurrentw import PoQgsCurrentW from .pomodules.poqgsstations import PoQgsStations +INFIX = ", ' - ', " + # noinspection PyMethodMayBeStatic class PoRunner(object): @@ -26,6 +28,72 @@ class PoRunner(object): self.connect_stations_signals() self.connect_waterlevels_signals() + # basemap ----------------------------------------------------------------- + + def disconnectStations(self): + print("disconnectStations") + self.stations = None + self.ui.cbStationsVisible.setChecked(False) + + # basemap signals --------------------------------------------------------- + + def _basemapCreate(self, path, name, disconnect: Callable[[], None]) -> None | QgsVectorLayer: + print("_basemapCreate: %s" % (name,)) + path = os.path.join(self.local_dir, "basemap", path) + basemap = QgsVectorLayer(path, name, "ogr") + + if not basemap.isValid(): + print("_basemapCreate: QgsVectorLayer nicht gültig: path=%s, name=%s" % (path, name)) + return None + + # disconnect setzen + # noinspection PyUnresolvedReferences + basemap.willBeDeleted.connect(disconnect) + + # zur Instanz hinzufügen + QgsProject.instance().addMapLayer(basemap, False) + + # zum LayerTree hinzufügen + layer_tree = self.iface.layerTreeCanvasBridge().rootGroup() + layer_tree.insertChildNode(-1, QgsLayerTreeLayer(basemap)) + + return basemap + + def connect_basemap_signals(self): + print("connect_basemap_signals") + self.ui.cbBasemapLines.toggled.connect(self.cbBasemapLinesToggled) + self.ui.cbBasemapAreas.toggled.connect(self.cbBasemapAreasToggled) + + def cbBasemapLinesToggled(self): + checked = self.ui.cbBasemapLines.isChecked() + print("cbBasemapLinesToggled: %s" % (checked,)) + + if self.lines is None and checked: + self.lines = self._basemapCreate("waters.gpkg|layername=water_l", "Flüsse", self.disconnectBasemapLines) + + if self.lines is not None: + self._layerSetVisible(self.lines, checked) + + def cbBasemapAreasToggled(self): + checked = self.ui.cbBasemapAreas.isChecked() + print("cbBasemapAreasToggled: %s" % (checked,)) + + if self.areas is None and checked: + self.areas = self._basemapCreate("waters.gpkg|layername=water_f", "Flächen", self.disconnectBasemapAreas) + + if self.areas is not None: + self._layerSetVisible(self.areas, checked) + + def disconnectBasemapLines(self): + print("disconnectBasemapLines") + self.lines = None + self.ui.cbBasemapLines.setChecked(False) + + def disconnectBasemapAreas(self): + print("disconnectBasemapAreas") + self.areas = None + self.ui.cbBasemapAreas.setChecked(False) + # stations ---------------------------------------------------------------- def loadStations(self): @@ -33,15 +101,188 @@ class PoRunner(object): reader = PoQgsStations() features = reader.getStationsFeatures() self.stations = self._layerFromReader(reader.fields, reader.crs, features, "Stationen") + self._stationsUpdateLabeling() self._layerShow(self.stations, "styles/label_stations.qml", self.disconnectStations) + # noinspection DuplicatedCode + def _stationsUpdateLabeling(self): + fields = [] + if self.ui.cbStationsName.isChecked(): + fields.append("shortname") + if self.ui.cbStationsNumber.isChecked(): + fields.append("number") + if self.ui.cbStationsAgency.isChecked(): + fields.append("agency") + if self.ui.cbStationsKm.isChecked(): + fields.append("km") + if self.ui.cbStationsWater.isChecked(): + fields.append("water") + self._layerUpdateLabeling(self.stations, fields) + + # stations signals -------------------------------------------------------- + + def connect_stations_signals(self): + print("connect_stations_signals") + # noinspection DuplicatedCode + self.ui.cbStationsVisible.toggled.connect(self.cbStationsVisibleToggled) + self.ui.cbStationsName.toggled.connect(self.cbStationsNameToggled) + self.ui.cbStationsNumber.toggled.connect(self.cbStationsNumberToggled) + self.ui.cbStationsAgency.toggled.connect(self.cbStationsAgencyToggled) + self.ui.cbStationsKm.toggled.connect(self.cbStationsKmToggled) + self.ui.cbStationsWater.toggled.connect(self.cbStationsWaterToggled) + + def cbStationsVisibleToggled(self): + visible = self.ui.cbStationsVisible.isChecked() + print("cbStationsVisibleToggled: %s" % (visible,)) + + if self.stations is None and visible: + self.loadStations() + + if self.stations is not None: + self.stations.setLabelsEnabled(visible) + self._layerSetVisible(self.stations, visible) + self._layerRefresh(self.stations) + + def cbStationsNameToggled(self): + checked = self.ui.cbStationsName.isChecked() + print("cbStationsNameToggled: %s" % (checked,)) + self._stationsUpdateLabeling() + + def cbStationsNumberToggled(self): + checked = self.ui.cbStationsNumber.isChecked() + print("cbStationsNumberToggled: %s" % (checked,)) + self._stationsUpdateLabeling() + + def cbStationsAgencyToggled(self): + checked = self.ui.cbStationsAgency.isChecked() + print("cbStationsAgencyToggled: %s" % (checked,)) + self._stationsUpdateLabeling() + + def cbStationsKmToggled(self): + checked = self.ui.cbStationsKm.isChecked() + print("cbStationsKmToggled: %s" % (checked,)) + self._stationsUpdateLabeling() + + def cbStationsWaterToggled(self): + checked = self.ui.cbStationsWater.isChecked() + print("cbStationsWaterToggled: %s" % (checked,)) + self._stationsUpdateLabeling() + + # waterlevels ------------------------------------------------------------- + def loadWaterlevels(self): print("loadWaterlevels") reader = PoQgsCurrentW() features = reader.getCurrentWFeatures() self.waterlevels = self._layerFromReader(reader.fields, reader.crs, features, "Wasserstandinformationen") + self._waterlevelsUpdateLabeling() self._layerShow(self.waterlevels, "styles/label_currentw.qml", self.disconnectWaterlevels) + # noinspection DuplicatedCode + def _waterlevelsUpdateLabeling(self): + fields = [] + if self.ui.cbWaterlevelsName.isChecked(): + fields.append("shortname") + if self.ui.cbWaterlevelsNumber.isChecked(): + fields.append("number") + if self.ui.cbWaterlevelsAgency.isChecked(): + fields.append("agency") + if self.ui.cbWaterlevelsTimestamp.isChecked(): + fields.append("timestamp") + if self.ui.cbWaterlevelsValue.isChecked(): + fields.append("value") + if self.ui.cbWaterlevelsMean.isChecked(): + fields.append("stateMnwMhw") + if self.ui.cbWaterlevelsAbsolute.isChecked(): + fields.append("stateNswHsw") + self._layerUpdateLabeling(self.waterlevels, fields) + + # waterlevels signals ----------------------------------------------------- + + def _layerSetVisible(self, basemap: QgsVectorLayer, visible): + print("_layerSetVisible: %s => %s" % (basemap.name, visible)) + layer_tree = QgsProject.instance().layerTreeRoot().findLayer(basemap.id()) + layer_tree.setItemVisibilityChecked(visible) + self._layerRefresh(basemap) + + def connect_waterlevels_signals(self): + print("connect_waterlevels_signals") + # noinspection DuplicatedCode + self.ui.cbWaterlevelsVisible.toggled.connect(self.cbWaterlevelsVisibleToggled) + self.ui.cbWaterlevelsName.toggled.connect(self.cbWaterlevelsNameToggled) + self.ui.cbWaterlevelsNumber.toggled.connect(self.cbWaterlevelsNumberToggled) + self.ui.cbWaterlevelsAgency.toggled.connect(self.cbWaterlevelsAgencyToggled) + self.ui.cbWaterlevelsTimestamp.toggled.connect(self.cbWaterlevelsTimestampToggled) + self.ui.cbWaterlevelsValue.toggled.connect(self.cbWaterlevelsValueToggled) + self.ui.cbWaterlevelsMean.toggled.connect(self.cbWaterlevelsMeanToggled) + self.ui.cbWaterlevelsAbsolute.toggled.connect(self.cbWaterlevelsAbsoluteToggled) + + def cbWaterlevelsVisibleToggled(self): + visible = self.ui.cbWaterlevelsVisible.isChecked() + print("cbWaterlevelsVisibleToggled: %s" % (visible,)) + + if self.waterlevels is None: + self.loadWaterlevels() + + if self.waterlevels is not None: + self.waterlevels.setLabelsEnabled(visible) + self._layerSetVisible(self.waterlevels, visible) + self._layerRefresh(self.waterlevels) + + def cbWaterlevelsNameToggled(self): + checked = self.ui.cbWaterlevelsName.isChecked() + print("cbWaterlevelsNameName: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsNumberToggled(self): + checked = self.ui.cbWaterlevelsNumber.isChecked() + print("cbWaterlevelsNameNumber: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsAgencyToggled(self): + checked = self.ui.cbWaterlevelsAgency.isChecked() + print("cbWaterlevelsNameAgency: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsTimestampToggled(self): + checked = self.ui.cbWaterlevelsTimestamp.isChecked() + print("cbWaterlevelsTimestampToggled: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsValueToggled(self): + checked = self.ui.cbWaterlevelsValue.isChecked() + print("cbWaterlevelsValueToggled: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsMeanToggled(self): + checked = self.ui.cbWaterlevelsMean.isChecked() + print("cbWaterlevelsMeanToggled: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + def cbWaterlevelsAbsoluteToggled(self): + checked = self.ui.cbWaterlevelsAbsolute.isChecked() + print("cbWaterlevelsAbsoluteToggled: %s" % (checked,)) + self._waterlevelsUpdateLabeling() + + # def rbValueChanged(self, button): + # print("rbValueChanged") + # if self.layer_waterlevels is None: + # self.loadWaterlevels() + # + # if button.objectName() == "rbShowTrend": + # self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_trend.qml")) + # elif button.objectName() == "rbShowAbsValues": + # self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_absvalue.qml")) + # + # self.cbWaterlevelsVisibleToggled() + + def disconnectWaterlevels(self): + print("disconnectWaterlevels") + self.waterlevels = None + self.ui.cbWaterlevelsVisible.setChecked(False) + + # layers ------------------------------------------------------------------ + def _layerFromReader(self, fields, crs, features, title) -> None | QgsVectorLayer: print("_layerFromReader") if features is None: @@ -88,120 +329,23 @@ class PoRunner(object): self._layerSetVisible(layer, True) self._layerRefresh(layer) - # stations signals -------------------------------------------------------- + def _layerUpdateLabeling(self, layer, fields): + labeling = QgsVectorLayerSimpleLabeling(QgsPalLayerSettings()) - def connect_stations_signals(self): - print("connect_stations_signals") - self.ui.cbStationsVisible.toggled.connect(self.cbStationsVisibleToggled) - self.ui.cbStationsName.toggled.connect(self.cbStationsNameToggled) - self.ui.cbStationsNumber.toggled.connect(self.cbStationsNumberToggled) - self.ui.cbStationsAgency.toggled.connect(self.cbStationsAgencyToggled) - self.ui.cbStationsKm.toggled.connect(self.cbStationsKmToggled) - self.ui.cbStationsWater.toggled.connect(self.cbStationsWaterToggled) + # Anführungszeichen um Feldnamen anbringen + fields_quoted = ['"%s"' % (field,) for field in fields] - def cbStationsVisibleToggled(self): - visible = self.ui.cbStationsVisible.isChecked() - print("cbStationsVisibleToggled: %s" % (visible,)) + # Feldnamen zu einem Minus-getrennten String zusammenbauen + expression = ", ' - ', ".join(fields_quoted) - if self.stations is None and visible: - self.loadStations() + settings = labeling.settings() + settings.fieldName = "concat(" + expression + ")" + settings.isExpression = True - if self.stations is not None: - self.stations.setLabelsEnabled(visible) - self._layerSetVisible(self.stations, visible) - self._layerRefresh(self.stations) + layer.setLabeling(QgsVectorLayerSimpleLabeling(settings)) + layer.setLabelsEnabled(True) - def cbStationsNameToggled(self): - checked = self.ui.cbStationsName.isChecked() - print("cbStationsNameToggled: %s" % (checked,)) - # TODO - - def cbStationsNumberToggled(self): - checked = self.ui.cbStationsNumber.isChecked() - print("cbStationsNumberToggled: %s" % (checked,)) - # TODO - - def cbStationsAgencyToggled(self): - checked = self.ui.cbStationsAgency.isChecked() - print("cbStationsAgencyToggled: %s" % (checked,)) - # TODO - - def cbStationsKmToggled(self): - checked = self.ui.cbStationsKm.isChecked() - print("cbStationsKmToggled: %s" % (checked,)) - # TODO - - def cbStationsWaterToggled(self): - checked = self.ui.cbStationsWater.isChecked() - print("cbStationsWaterToggled: %s" % (checked,)) - # TODO - - def disconnectStations(self): - print("disconnectStations") - self.stations = None - self.ui.cbStationsVisible.setChecked(False) - - # basemap ----------------------------------------------------------------- - - def _basemapCreate(self, path, name, disconnect: Callable[[], None]) -> None | QgsVectorLayer: - print("_basemapCreate: %s" % (name,)) - path = os.path.join(self.local_dir, "basemap", path) - basemap = QgsVectorLayer(path, name, "ogr") - - if not basemap.isValid(): - print("_basemapCreate: QgsVectorLayer nicht gültig: path=%s, name=%s" % (path, name)) - return None - - # disconnect setzen - basemap.willBeDeleted.connect(disconnect) - - # zur Instanz hinzufügen - QgsProject.instance().addMapLayer(basemap, False) - - # zum LayerTree hinzufügen - layer_tree = self.iface.layerTreeCanvasBridge().rootGroup() - layer_tree.insertChildNode(-1, QgsLayerTreeLayer(basemap)) - - return basemap - - # basemap signals --------------------------------------------------------- - - def connect_basemap_signals(self): - print("connect_basemap_signals") - self.ui.cbBasemapLines.toggled.connect(self.cbBasemapLinesToggled) - self.ui.cbBasemapAreas.toggled.connect(self.cbBasemapAreasToggled) - - def cbBasemapLinesToggled(self): - checked = self.ui.cbBasemapLines.isChecked() - print("cbBasemapLinesToggled: %s" % (checked,)) - - if self.lines is None and checked: - self.lines = self._basemapCreate("waters.gpkg|layername=water_l", "Flüsse", self.disconnectBasemapLines) - - if self.lines is not None: - self._layerSetVisible(self.lines, checked) - - def cbBasemapAreasToggled(self): - checked = self.ui.cbBasemapAreas.isChecked() - print("cbBasemapAreasToggled: %s" % (checked,)) - - if self.areas is None and checked: - self.areas = self._basemapCreate("waters.gpkg|layername=water_f", "Flächen", self.disconnectBasemapAreas) - - if self.areas is not None: - self._layerSetVisible(self.areas, checked) - - def disconnectBasemapLines(self): - print("disconnectBasemapLines") - self.lines = None - self.ui.cbBasemapLines.setChecked(False) - - def disconnectBasemapAreas(self): - print("disconnectBasemapAreas") - self.areas = None - self.ui.cbBasemapAreas.setChecked(False) - - # layers ------------------------------------------------------------------ + self._layerRefresh(layer) def _layerRefresh(self, layer): print("_layerRefresh") @@ -209,74 +353,3 @@ class PoRunner(object): layer.triggerRepaint() else: self.iface.mapCanvas().refresh() - - def _layerSetVisible(self, basemap: QgsVectorLayer, visible): - print("_layerSetVisible: %s => %s" % (basemap.name, visible)) - layer_tree = QgsProject.instance().layerTreeRoot().findLayer(basemap.id()) - layer_tree.setItemVisibilityChecked(visible) - self._layerRefresh(basemap) - - # waterlevels signals ----------------------------------------------------- - - def connect_waterlevels_signals(self): - print("connect_waterlevels_signals") - self.ui.cbWaterlevelsVisible.toggled.connect(self.cbWaterlevelsVisibleToggled) - self.ui.cbWaterlevelsName.toggled.connect(self.cbWaterlevelsNameToggled) - self.ui.cbWaterlevelsTimestamp.toggled.connect(self.cbWaterlevelsTimestampToggled) - self.ui.cbWaterlevelsValue.toggled.connect(self.cbWaterlevelsValueToggled) - self.ui.cbWaterlevelsMean.toggled.connect(self.cbWaterlevelsMeanToggled) - self.ui.cbWaterlevelsAbsolute.toggled.connect(self.cbWaterlevelsAbsoluteToggled) - - def cbWaterlevelsVisibleToggled(self): - visible = self.ui.cbWaterlevelsVisible.isChecked() - print("cbWaterlevelsVisibleToggled: %s" % (visible,)) - - if self.waterlevels is None: - self.loadWaterlevels() - - if self.waterlevels is not None: - self.waterlevels.setLabelsEnabled(visible) - self._layerSetVisible(self.waterlevels, visible) - self._layerRefresh(self.waterlevels) - - def cbWaterlevelsNameToggled(self): - checked = self.ui.cbWaterlevelsName.isChecked() - print("cbWaterlevelsNameToggled: %s" % (checked,)) - # TODO - - def cbWaterlevelsTimestampToggled(self): - checked = self.ui.cbWaterlevelsTimestamp.isChecked() - print("cbWaterlevelsTimestampToggled: %s" % (checked,)) - # TODO - - def cbWaterlevelsValueToggled(self): - checked = self.ui.cbWaterlevelsValue.isChecked() - print("cbWaterlevelsValueToggled: %s" % (checked,)) - # TODO - - def cbWaterlevelsMeanToggled(self): - checked = self.ui.cbWaterlevelsMean.isChecked() - print("cbWaterlevelsMeanToggled: %s" % (checked,)) - # TODO - - def cbWaterlevelsAbsoluteToggled(self): - checked = self.ui.cbWaterlevelsAbsolute.isChecked() - print("cbWaterlevelsAbsoluteToggled: %s" % (checked,)) - # TODO - - def disconnectWaterlevels(self): - print("disconnectWaterlevels") - self.waterlevels = None - self.ui.cbWaterlevelsVisible.setChecked(False) - - # def rbValueChanged(self, button): - # print("rbValueChanged") - # if self.layer_waterlevels is None: - # self.loadWaterlevels() - # - # if button.objectName() == "rbShowTrend": - # self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_trend.qml")) - # elif button.objectName() == "rbShowAbsValues": - # self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_absvalue.qml")) - # - # self.cbWaterlevelsVisibleToggled() diff --git a/pomodules/pocurrentw.py b/pomodules/pocurrentw.py index ae343dd..54cd4e6 100644 --- a/pomodules/pocurrentw.py +++ b/pomodules/pocurrentw.py @@ -33,6 +33,8 @@ class PoCurrentW(object): 'attributes': { 'uuid': station_json['uuid'], 'shortname': station_json['shortname'], + 'number': station_json['number'], + 'agency': station_json['agency'], 'timestamp': station_json['timeseries'][0]['currentMeasurement']['timestamp'], 'value': station_json['timeseries'][0]['currentMeasurement']['value'], 'stateMnwMhw': station_json['timeseries'][0]['currentMeasurement']['stateMnwMhw'], diff --git a/pomodules/poqgscurrentw.py b/pomodules/poqgscurrentw.py index ba9279a..8476afe 100644 --- a/pomodules/poqgscurrentw.py +++ b/pomodules/poqgscurrentw.py @@ -16,6 +16,9 @@ class PoQgsCurrentW(PoCurrentW): print("getCurrentWFeatures: Erzeuge Features...") self.fields = QgsFields() + self.fields.append(QgsField('shortname', QVariant.String)) + self.fields.append(QgsField('number', QVariant.Int)) + self.fields.append(QgsField('agency', QVariant.String)) self.fields.append(QgsField('timestamp', QVariant.DateTime)) self.fields.append(QgsField('value', QVariant.Double)) self.fields.append(QgsField('stateMnwMhw', QVariant.String)) @@ -36,6 +39,9 @@ class PoQgsCurrentW(PoCurrentW): latitude = station['geometry']['latitude'] feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(longitude, latitude))) + feature.setAttribute('shortname', station['attributes']['shortname']) + feature.setAttribute('number', station['attributes']['number']) + feature.setAttribute('agency', station['attributes']['agency']) feature.setAttribute('timestamp', station['attributes']['timestamp']) feature.setAttribute('value', station['attributes']['value']) feature.setAttribute('stateMnwMhw', station['attributes']['stateMnwMhw'])