0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

WIP hierarchy on app level

This commit is contained in:
2025-04-05 19:48:18 +02:00
parent 6f2e01b420
commit fb329eb147
2 changed files with 109 additions and 17 deletions

View File

@ -1,5 +1,8 @@
# pylint: disable=no-name-in-module
from __future__ import annotations
from collections import defaultdict
import pyqtgraph as pg
from abc import ABC, abstractmethod
@ -331,17 +334,77 @@ class WidgetHierarchy:
if only_bec_widgets and not isinstance(child, BECConnector):
continue
if WidgetHierarchy._get_becwidget_ancestor(child) == widget:
child_prefix = prefix + " └─ "
WidgetHierarchy.print_widget_hierarchy(
child,
indent=indent + 1,
grab_values=grab_values,
prefix=child_prefix,
exclude_internal_widgets=exclude_internal_widgets,
only_bec_widgets=only_bec_widgets,
show_parent=show_parent,
)
# if WidgetHierarchy._get_becwidget_ancestor(child) == widget:
child_prefix = prefix + " └─ "
WidgetHierarchy.print_widget_hierarchy(
child,
indent=indent + 1,
grab_values=grab_values,
prefix=child_prefix,
exclude_internal_widgets=exclude_internal_widgets,
only_bec_widgets=only_bec_widgets,
show_parent=show_parent,
)
@staticmethod
def print_becconnector_hierarchy_from_app():
"""
Enumerate ALL widgets in the QApplication, pick only BECConnector objects,
then build a parent->child graph where each child's 'parent' is the closest
BECConnector ancestor. Finally, print the entire hierarchy from the root(s).
The result is a single, consolidated hierarchy for your entire running GUI.
"""
# 1. Gather ALL widgets from the running QApplication
all_widgets = QApplication.allWidgets()
# 2. Filter out those which are BECConnector
bec_widgets = [w for w in all_widgets if isinstance(w, BECConnector)]
# 3. Build a mapping parent -> list of children,
# where 'parent' is the nearest BECConnector ancestor
parent_map = defaultdict(list)
for w in bec_widgets:
parent_bec = WidgetHierarchy._get_becwidget_ancestor(w)
parent_map[parent_bec].append(w)
# 4. Recursively print the hierarchy (DFS or BFS).
# Start from items whose nearest BECConnector parent is None.
def print_tree(parent, prefix=""):
children = parent_map[parent]
for i, child in enumerate(children):
# Figure out indentation/prefix
# We'll do a "└─" for the last child at that level, "├─" otherwise
connector_class = child.__class__.__name__
connector_name = child.objectName() or connector_class
# The parent label
if parent is None:
parent_label = "None"
else:
parent_label = parent.objectName() or parent.__class__.__name__
# Print the line for this child
line = f"{connector_class} ({connector_name}) parent={parent_label}"
if i == len(children) - 1:
print(prefix + "└─ " + line)
next_prefix = prefix + " "
else:
print(prefix + "├─ " + line)
next_prefix = prefix + ""
# Recurse
print_tree(child, prefix=next_prefix)
# 5. Print top-level roots (those whose parent is None)
# Each top-level root is printed without indentation/prefix.
for root in parent_map[None]:
root_class = root.__class__.__name__
root_name = root.objectName() or root_class
print(f"{root_class} ({root_name}) parent=None")
# Recurse into its children
print_tree(root, prefix=" ")
@staticmethod
def _get_becwidget_ancestor(widget):
@ -356,6 +419,19 @@ class WidgetHierarchy:
parent = parent.parent()
return None
# @staticmethod
# def _get_becwidget_ancestor(widget):
# """
# Traverse up the parent chain to find the nearest BECConnector.
# Returns None if none is found.
# """
# parent = widget.parent()
# while parent is not None:
# if isinstance(parent, BECConnector):
# return parent
# parent = parent.parent()
# return None
@staticmethod
def export_config_to_dict(
widget: QWidget,

View File

@ -6,6 +6,8 @@ from typing import Literal
import lmfit
import numpy as np
import pyqtgraph as pg
from PySide6.QtWidgets import QApplication, QPushButton
from bec_lib import bec_logger, messages
from bec_lib.endpoints import MessageEndpoints
from pydantic import Field, ValidationError, field_validator
@ -18,6 +20,7 @@ from bec_widgets.utils.colors import Colors, set_theme
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
from bec_widgets.utils.settings_dialog import SettingsDialog
from bec_widgets.utils.toolbar import MaterialIconAction
from bec_widgets.utils.widget_io import WidgetHierarchy
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
from bec_widgets.widgets.dap.lmfit_dialog.lmfit_dialog import LMFitDialog
from bec_widgets.widgets.plots.plot_base import PlotBase
@ -1592,32 +1595,45 @@ class Waveform(PlotBase):
super().cleanup()
class DemoApp(BECMainWindow): # pragma: no cover
class DemoApp(QMainWindow): # pragma: no cover
def __init__(self):
super().__init__()
self.setWindowTitle("Waveform Demo")
self.resize(800, 600)
self.main_widget = QWidget()
self.main_widget = QWidget(self)
self.layout = QHBoxLayout(self.main_widget)
self.setCentralWidget(self.main_widget)
self.waveform_popup = Waveform(popups=True)
self.waveform_popup.plot(y_name="monitor_async")
self.waveform_side = Waveform(popups=False)
self.waveform_side = Waveform(popups=False, parent=self.main_widget)
self.waveform_side.plot(y_name="bpm4i", y_entry="bpm4i", dap="GaussianModel")
self.waveform_side.plot(y_name="bpm3a", y_entry="bpm3a")
self.hierarchy_button = QPushButton()
self.hierarchy_button.setText("Hierarchy")
self.hierarchy_button.clicked.connect(self.hierarchy)
self.layout.addWidget(self.waveform_side)
self.layout.addWidget(self.waveform_popup)
self.layout.addWidget(self.hierarchy_button)
def hierarchy(self):
print("getting app")
WidgetHierarchy.print_becconnector_hierarchy_from_app() # , only_bec_widgets=True)
print("getting of side waveform")
WidgetHierarchy.print_widget_hierarchy(self.waveform_side, only_bec_widgets=True)
if __name__ == "__main__": # pragma: no cover
import sys
from bec_widgets.utils.bec_qapp import BECApplication
app = BECApplication(sys.argv)
# from bec_widgets.utils.bec_qapp import BECApplication
#
# app = BECApplication(sys.argv)
app = QApplication(sys.argv)
set_theme("dark")
widget = DemoApp()
widget.show()