From 1f534fac83031fa7eeb7eb2a05bab4de92b217e7 Mon Sep 17 00:00:00 2001 From: wakonig_k Date: Wed, 20 May 2026 20:40:02 +0200 Subject: [PATCH] wip --- bec_widgets/utils/ui_loader.py | 46 +++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/bec_widgets/utils/ui_loader.py b/bec_widgets/utils/ui_loader.py index 17c3bdb9..857601e2 100644 --- a/bec_widgets/utils/ui_loader.py +++ b/bec_widgets/utils/ui_loader.py @@ -1,6 +1,6 @@ from bec_lib.logger import bec_logger from qtpy import PYSIDE6 -from qtpy.QtCore import QFile, QIODevice +from qtpy.QtCore import QEvent, QFile, QIODevice, QObject from bec_widgets.utils.plugin_utils import get_designer_plugin @@ -9,16 +9,56 @@ logger = bec_logger.logger if PYSIDE6: from qtpy.QtUiTools import QUiLoader + class _LoadedUiCloser(QObject): + """Forward root close events to widgets instantiated by ``QUiLoader``. + + Destroying a parent widget does not guarantee ``closeEvent`` is delivered to + every child widget. Some of our designer plugins rely on ``closeEvent`` / + ``cleanup`` to unregister callbacks, so explicitly close loaded descendants + when the loaded form itself is closed. + """ + + def __init__(self, root_widget): + super().__init__(root_widget) + self._root_widget = root_widget + self._widgets = [] + root_widget.installEventFilter(self) + + def register_widget(self, widget): + if widget is None or widget is self._root_widget: + return + self._widgets.append(widget) + + def eventFilter(self, watched, event): + if watched is self._root_widget and event.type() == QEvent.Close: + for widget in reversed(self._widgets): + try: + widget.close() + except RuntimeError: + continue + return super().eventFilter(watched, event) + class CustomUiLoader(QUiLoader): def __init__(self, baseinstance): super().__init__(baseinstance) self.baseinstance = baseinstance + self._closer = _LoadedUiCloser(baseinstance) if baseinstance is not None else None def createWidget(self, class_name, parent=None, name=""): + if parent is None and self.baseinstance is not None: + return self.baseinstance + + widget_parent = parent if parent is not None else self.baseinstance widget = get_designer_plugin(class_name, raise_on_missing=False) if widget is not None: - return widget(self.baseinstance) - return super().createWidget(class_name, self.baseinstance, name) + created_widget = widget(widget_parent) + created_widget.setObjectName(name) + else: + created_widget = super().createWidget(class_name, widget_parent, name) + + if self._closer is not None: + self._closer.register_widget(created_widget) + return created_widget class UILoader: