Ein langer Tab (Druck-Tab mit aufgeklapptem Basemap-Bereich) schob den unteren Rand des QGIS-Fensters aus dem Bildschirm, weil Qt für das Dock die Höhe des höchsten Tabs verlangt. BaseDockWidget.setWidget packt jetzt jeden Tab eines QTabWidget in einen QScrollArea; das wirkt auch für Fachplugins, die ihre Tabs selbst aufbauen. QScrollArea/QFrame im qt_wrapper ergänzt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
173 lines
5.7 KiB
Python
173 lines
5.7 KiB
Python
"""
|
|
sn_basis/ui/base_dockwidget.py
|
|
|
|
Basis-Dockwidget für alle LNO-Module.
|
|
"""
|
|
|
|
from sn_basis.functions.qt_wrapper import QDockWidget, QTabWidget
|
|
from sn_basis.functions.message_wrapper import warning, error
|
|
from sn_basis.functions.qt_wrapper import (
|
|
QDockWidget,
|
|
QTabWidget,
|
|
QScrollArea,
|
|
FrameNoFrame,
|
|
Qt,
|
|
DockWidgetMovable,
|
|
DockWidgetFloatable,
|
|
DockWidgetClosable,
|
|
DockAreaLeft,
|
|
DockAreaRight,
|
|
)
|
|
|
|
|
|
def _inhalt(seite):
|
|
"""Tab-Instanz einer Reiterseite; liegt sie in einem Scroll-Bereich, dessen Inhalt."""
|
|
if isinstance(seite, QScrollArea):
|
|
return seite.widget()
|
|
return seite
|
|
|
|
|
|
def tabs_mit_scrollbereich(tab_widget) -> None:
|
|
"""Packt jeden Tab eines QTabWidget in einen mitwachsenden Scroll-Bereich (Basis #104).
|
|
|
|
Ohne Scroll-Bereich verlangt Qt für das Dock mindestens die Höhe des höchsten Tabs; ist
|
|
der Tab höher als der Bildschirm, schiebt QGIS seinen unteren Fensterrand aus dem Bild.
|
|
Tabs, die schon in einem Scroll-Bereich liegen, bleiben unverändert.
|
|
"""
|
|
if not callable(getattr(tab_widget, "count", None)) or not callable(getattr(tab_widget, "insertTab", None)):
|
|
return
|
|
aktuell = tab_widget.currentIndex()
|
|
for index in range(tab_widget.count()):
|
|
seite = tab_widget.widget(index)
|
|
if seite is None or isinstance(seite, QScrollArea):
|
|
continue
|
|
titel = tab_widget.tabText(index)
|
|
bereich = QScrollArea()
|
|
bereich.setWidgetResizable(True)
|
|
bereich.setFrameShape(FrameNoFrame)
|
|
tab_widget.removeTab(index)
|
|
bereich.setWidget(seite)
|
|
tab_widget.insertTab(index, bereich, titel)
|
|
tab_widget.setCurrentIndex(aktuell)
|
|
|
|
|
|
class BaseDockWidget(QDockWidget):
|
|
"""
|
|
Basis-Dockwidget für alle LNO-Module.
|
|
|
|
- Titel wird automatisch aus base_title + subtitle erzeugt
|
|
- Tabs werden dynamisch aus der Klassenvariable 'tabs' erzeugt
|
|
- Die zugehörige Toolbar-Action wird beim Schließen zurückgesetzt
|
|
- Jeder Tab liegt in einem Scroll-Bereich (``setWidget``), auch wenn ein Fachplugin
|
|
seine Tabs selbst aufbaut (Basis #104)
|
|
"""
|
|
|
|
base_title = "LNO Sachsen"
|
|
tabs = [] # Liste von Tab-Klassen
|
|
action = None # Referenz auf die Toolbar-Action
|
|
|
|
def __init__(self, parent=None, subtitle=""):
|
|
super().__init__(parent)
|
|
# -----------------------------------------------------
|
|
# Dock-Konfiguration (WICHTIG)
|
|
# -----------------------------------------------------
|
|
self.setFeatures(
|
|
DockWidgetMovable
|
|
| DockWidgetFloatable
|
|
| DockWidgetClosable
|
|
)
|
|
|
|
self.setAllowedAreas(
|
|
DockAreaLeft
|
|
| DockAreaRight
|
|
)
|
|
|
|
# -----------------------------------------------------
|
|
# Titel setzen
|
|
# -----------------------------------------------------
|
|
try:
|
|
title = (
|
|
self.base_title
|
|
if not subtitle
|
|
else f"{self.base_title} | {subtitle}"
|
|
)
|
|
self.setWindowTitle(title)
|
|
except Exception as e:
|
|
warning("Titel konnte nicht gesetzt werden", str(e))
|
|
|
|
# -----------------------------------------------------
|
|
# Tabs erzeugen
|
|
# -----------------------------------------------------
|
|
try:
|
|
tab_widget = QTabWidget()
|
|
|
|
for tab_class in self.tabs:
|
|
try:
|
|
tab_instance = tab_class()
|
|
tab_title = getattr(
|
|
tab_class,
|
|
"tab_title",
|
|
tab_class.__name__,
|
|
)
|
|
tab_widget.addTab(tab_instance, tab_title)
|
|
except Exception as e:
|
|
error(
|
|
"Tab konnte nicht geladen werden",
|
|
f"{tab_class}: {e}",
|
|
)
|
|
|
|
self.setWidget(tab_widget)
|
|
|
|
except Exception as e:
|
|
error(
|
|
"Tab-Widget konnte nicht initialisiert werden",
|
|
str(e),
|
|
)
|
|
|
|
# ---------------------------------------------------------
|
|
# Inhalt setzen
|
|
# ---------------------------------------------------------
|
|
|
|
def setWidget(self, widget):
|
|
"""Wie ``QDockWidget.setWidget``; die Tabs eines QTabWidget bekommen je einen Scroll-Bereich."""
|
|
if widget is not None:
|
|
try:
|
|
tabs_mit_scrollbereich(widget)
|
|
except Exception as e:
|
|
warning("Scroll-Bereich konnte nicht angelegt werden", str(e))
|
|
super().setWidget(widget)
|
|
|
|
# ---------------------------------------------------------
|
|
# Dock schließen
|
|
# ---------------------------------------------------------
|
|
|
|
def closeEvent(self, event):
|
|
"""
|
|
Wird aufgerufen, wenn das Dock geschlossen wird.
|
|
Setzt die zugehörige Toolbar-Action zurück.
|
|
"""
|
|
try:
|
|
tab_widget = self.widget()
|
|
if tab_widget and hasattr(tab_widget, "count") and hasattr(tab_widget, "widget"):
|
|
for index in range(tab_widget.count()):
|
|
tab = _inhalt(tab_widget.widget(index))
|
|
cleanup = getattr(tab, "cleanup", None)
|
|
if callable(cleanup):
|
|
try:
|
|
cleanup()
|
|
except Exception:
|
|
pass
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
if self.action:
|
|
self.action.setChecked(False)
|
|
except Exception as e:
|
|
warning(
|
|
"Toolbar-Status konnte nicht zurückgesetzt werden",
|
|
str(e),
|
|
)
|
|
|
|
super().closeEvent(event)
|