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

wip QAPP with QMainWindow with some example ui files, you need to manually change the ui file in the server to change ui

This commit is contained in:
2025-03-25 20:49:03 +01:00
parent 867ab574cb
commit ae3e2d7946
10 changed files with 738 additions and 26 deletions

View File

@ -634,6 +634,14 @@ class DarkModeButton(RPCBase):
"""
class DemoApp(RPCBase):
@rpc_call
def remove(self):
"""
Cleanup the BECConnector
"""
class DeviceBrowser(RPCBase):
@rpc_call
def remove(self):
@ -3513,3 +3521,60 @@ class WebsiteWidget(RPCBase):
"""
Go forward in the history
"""
class WindowWithUi(RPCBase):
"""This is just testing app wiht UI file which could be connected to RPC."""
@rpc_call
def new_dock_area(
self, name: str | None = None, geometry: tuple[int, int, int, int] | None = None
) -> "BECDockArea":
"""
Create a new dock area.
Args:
name(str): The name of the dock area.
geometry(tuple): The geometry parameters to be passed to the dock area.
Returns:
BECDockArea: The newly created dock area.
"""
@property
@rpc_call
def all_connections(self) -> list:
"""
None
"""
@rpc_call
def change_theme(self, theme):
"""
None
"""
@property
@rpc_call
def dock_area(self):
"""
None
"""
@rpc_call
def register_all_rpc(self):
"""
None
"""
@property
@rpc_call
def widget_list(self) -> list:
"""
Return a list of all widgets in the application.
"""
@rpc_call
def list_app_hierarchy(self):
"""
List the hierarchy of the application.
"""

View File

@ -199,7 +199,7 @@ class BECGuiClient(RPCBase):
self._auto_updates_enabled = True
self._auto_updates = None
self._killed = False
self._top_level: dict[str, client.BECDockArea] = {}
self._top_level: dict[str, RPCBase] = {} # TODO should be more general than just DockArea
self._startup_timeout = 0
self._gui_started_timer = None
self._gui_started_event = threading.Event()
@ -231,6 +231,8 @@ class BECGuiClient(RPCBase):
self._client.connector.register(
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
)
self._update_dynamic_namespace() # FIXME don't refresh the namespace
# TODO do a cleanup of the previous server...
@property
def windows(self) -> dict:

View File

@ -18,9 +18,10 @@ from redis.exceptions import RedisError
from bec_widgets.cli.rpc.rpc_register import RPCRegister
from bec_widgets.utils import BECDispatcher
from bec_widgets.utils.bec_connector import BECConnector
from bec_widgets.utils.bec_qapp import BECApplication
from bec_widgets.utils.error_popups import ErrorPopupUtility
from bec_widgets.widgets.containers.dock import BECDockArea
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow, WindowWithUi
messages = lazy_import("bec_lib.messages")
logger = bec_logger.logger
@ -57,7 +58,7 @@ class BECWidgetsCLIServer:
dispatcher: BECDispatcher = None,
client=None,
config=None,
gui_class: type[BECDockArea] = BECDockArea,
gui_class: type[BECDockArea, WindowWithUi] = BECDockArea,
gui_class_id: str = "bec",
) -> None:
self.status = messages.BECStatus.BUSY
@ -204,7 +205,10 @@ class SimpleFileLikeFromLogOutputFunc:
def _start_server(
gui_id: str, gui_class: BECDockArea, gui_class_id: str = "bec", config: str | None = None
gui_id: str,
gui_class: BECDockArea | WindowWithUi,
gui_class_id: str = "bec",
config: str | None = None,
):
if config:
try:
@ -230,14 +234,8 @@ def _start_server(
def main():
import argparse
import os
from qtpy.QtCore import QSize
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QApplication
import bec_widgets
parser = argparse.ArgumentParser(description="BEC Widgets CLI Server")
parser.add_argument("--id", type=str, default="test", help="The id of the server")
parser.add_argument(
@ -264,6 +262,8 @@ def main():
if args.gui_class == "BECDockArea":
gui_class = BECDockArea
elif args.gui_class == "MainWindow":
gui_class = WindowWithUi
else:
print(
"Please specify a valid gui_class to run. Use -h for help."
@ -273,27 +273,21 @@ def main():
with redirect_stdout(SimpleFileLikeFromLogOutputFunc(logger.info)):
with redirect_stderr(SimpleFileLikeFromLogOutputFunc(logger.error)):
app = QApplication(sys.argv)
app = BECApplication(sys.argv)
# set close on last window, only if not under control of client ;
# indeed, Qt considers a hidden window a closed window, so if all windows
# are hidden by default it exits
app.setQuitOnLastWindowClosed(not args.hide)
module_path = os.path.dirname(bec_widgets.__file__)
icon = QIcon()
icon.addFile(
os.path.join(module_path, "assets", "app_icons", "bec_widgets_icon.png"),
size=QSize(48, 48),
)
app.setWindowIcon(icon)
# store gui id within QApplication object, to make it available to all widgets
# store gui id within QApplication object, to make it available to all widgets #TODO not needed probably
app.gui_id = args.id
# args.id = "abff6"
server = _start_server(args.id, gui_class, args.gui_class_id, args.config)
# TODO to test other gui just change gui_class to something else such as WindowWithUi
server = _start_server(args.id, WindowWithUi, args.gui_class_id, args.config)
win = BECMainWindow(gui_id=f"{server.gui_id}:window")
win.setAttribute(Qt.WA_ShowWithoutActivating)
win.setWindowTitle("BEC")
# win.setWindowTitle("BEC")
RPCRegister().add_rpc(win)
gui = server.gui

View File

@ -0,0 +1,156 @@
from __future__ import annotations
import os
import random
import string
from typing import TYPE_CHECKING
from bec_lib import bec_logger
from bec_widgets.utils.bec_dispatcher import BECDispatcher
from bec_widgets.utils.bec_widget import BECWidget
from qtpy.QtCore import QSize
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QApplication
import collections
from collections.abc import Callable
from typing import TYPE_CHECKING, Union
import redis
from bec_lib.client import BECClient
from bec_lib.logger import bec_logger
from bec_lib.redis_connector import MessageObject, RedisConnector
from bec_lib.service_config import ServiceConfig
from qtpy.QtCore import QObject
from qtpy.QtCore import Signal
import bec_widgets
from bec_widgets.cli.rpc.rpc_register import RPCRegister
logger = bec_logger.logger
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
class BECApplication(QApplication):
"""
Custom QApplication class for BEC applications.
"""
def __init__(
self,
*args,
client=None,
config: str | ServiceConfig = None,
gui_id: str | None = None,
**kwargs,
):
super().__init__(*args, **kwargs)
self.gui_id = gui_id or self.generate_unique_identifier()
self.dispatcher = BECDispatcher(client=client, config=config)
self.rpc_register = RPCRegister()
self.client = self.dispatcher.client # fetch client from Dispatcher
# Indicate this is a BEC application
self.is_bec_app = True
self.setup_bec_icon()
self.register_all()
def setup_bec_icon(self):
icon = QIcon()
icon.addFile(
os.path.join(MODULE_PATH, "assets", "app_icons", "bec_widgets_icon.png"),
size=QSize(48, 48),
)
self.setWindowIcon(icon)
@staticmethod
def generate_unique_identifier(length: int = 4) -> str:
allowed_chars = string.ascii_lowercase + string.digits
return "".join(random.choices(allowed_chars, k=length))
# TODO not sure if needed
def register_all(self):
widgets = self.allWidgets()
all_connections = self.rpc_register.list_all_connections()
for widget in widgets:
if not isinstance(widget, BECWidget):
continue
gui_id = getattr(widget, "gui_id", None)
if gui_id and widget not in all_connections:
self.rpc_register.add_rpc(widget)
print(
f"[BECQApplication]: Registered widget {widget.__class__} with GUI ID: {gui_id}"
)
# TODO not sure if needed
def list_all_bec_widgets(self):
widgets = self.allWidgets()
bec_widgets = []
for widget in widgets:
if isinstance(widget, BECWidget):
bec_widgets.append(widget)
return bec_widgets
def list_hierarchy(self, only_bec_widgets: bool = True, show_parent: bool = True):
"""
List the hierarchy of all BECWidgets in this application.
Args:
only_bec_widgets (bool): If True, prints only BECWidgets. Non-BECWidgets are skipped but their children are still traversed.
show_parent (bool): If True, displays the immediate BECWidget ancestor for each item.
"""
bec_widgets = self.list_all_bec_widgets()
# Identify top-level BECWidgets (whose parent is not another BECWidget)
top_level = [
w for w in bec_widgets if not isinstance(self._get_becwidget_ancestor(w), BECWidget)
]
print("[BECQApplication]: Listing BECWidget hierarchy:")
for widget in top_level:
self._print_becwidget_hierarchy(
widget, indent=0, only_bec_widgets=only_bec_widgets, show_parent=show_parent
)
def _print_becwidget_hierarchy(self, widget, indent=0, only_bec_widgets=True, show_parent=True):
# Decide if this widget should be printed
is_bec = isinstance(widget, BECWidget)
print_this = (not only_bec_widgets) or is_bec
parent_info = ""
if show_parent and is_bec:
ancestor = self._get_becwidget_ancestor(widget)
if ancestor is not None:
parent_info = f" parent={ancestor.__class__.__name__}"
else:
parent_info = " parent=None"
if print_this:
prefix = " " * indent
print(
f"{prefix}- {widget.__class__.__name__} (objectName={widget.objectName()}){parent_info}"
)
# Always recurse so deeper BECWidgets aren't missed
for child in widget.children():
# Skip known non-BECWidgets if only_bec_widgets is True, but keep recursion
# We'll still call _print_becwidget_hierarchy to discover any BECWidget descendants.
self._print_becwidget_hierarchy(
child, indent + 2, only_bec_widgets=only_bec_widgets, show_parent=show_parent
)
def _get_becwidget_ancestor(self, widget):
"""
Climb the .parent() chain until finding another BECWidget, or None.
"""
p = widget.parent()
while p is not None:
if isinstance(p, BECWidget):
return p
p = p.parent()
return None
def shutdown(self):
self.dispatcher.disconnect_all()
super().shutdown()

View File

@ -0,0 +1,15 @@
import webbrowser
class BECWebLinksMixin:
@staticmethod
def open_bec_docs():
webbrowser.open("https://beamline-experiment-control.readthedocs.io/en/latest/")
@staticmethod
def open_bec_widgets_docs():
webbrowser.open("https://bec.readthedocs.io/projects/bec-widgets/en/latest/")
@staticmethod
def open_bec_bug_report():
webbrowser.open("https://gitlab.psi.ch/groups/bec/-/issues/")

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>824</width>
<height>1234</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="Waveform" name="waveform"/>
</item>
<item>
<widget class="BECDockArea" name="dock_area_2"/>
</item>
<item>
<widget class="BECDockArea" name="dock_area"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BECDockArea</class>
<extends>QWidget</extends>
<header>dock_area</header>
</customwidget>
<customwidget>
<class>Waveform</class>
<extends>QWidget</extends>
<header>waveform</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,262 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1718</width>
<height>1139</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="tabShape">
<enum>QTabWidget::TabShape::Rounded</enum>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTabWidget" name="central_tab">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="dock_area_tab">
<attribute name="title">
<string>Dock Area</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="BECDockArea" name="dock_area"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="vscode_tab">
<attribute name="icon">
<iconset theme="QIcon::ThemeIcon::Computer"/>
</attribute>
<attribute name="title">
<string>Visual Studio Code</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="VSCodeEditor" name="vscode"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1718</width>
<height>31</height>
</rect>
</property>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="action_BEC_docs"/>
<addaction name="action_BEC_widgets_docs"/>
<addaction name="action_bug_report"/>
</widget>
<widget class="QMenu" name="menuTheme">
<property name="title">
<string>Theme</string>
</property>
<addaction name="action_light"/>
<addaction name="action_dark"/>
</widget>
<addaction name="menuTheme"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dock_scan_control">
<property name="windowTitle">
<string>Scan Control</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="ScanControl" name="scan_control"/>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dock_status_2">
<property name="windowTitle">
<string>BEC Service Status</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="BECStatusBox" name="bec_status_box_2"/>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dock_queue">
<property name="windowTitle">
<string>Scan Queue</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_4">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="BECQueue" name="bec_queue">
<row/>
<column/>
<column/>
<column/>
<item row="0" column="0"/>
<item row="0" column="1"/>
<item row="0" column="2"/>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="action_BEC_docs">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
</property>
<property name="text">
<string>BEC Docs</string>
</property>
</action>
<action name="action_BEC_widgets_docs">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
</property>
<property name="text">
<string>BEC Widgets Docs</string>
</property>
</action>
<action name="action_bug_report">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DialogError"/>
</property>
<property name="text">
<string>Bug Report</string>
</property>
</action>
<action name="action_light">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Light</string>
</property>
</action>
<action name="action_dark">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Dark</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>WebsiteWidget</class>
<extends>QWebEngineView</extends>
<header>website_widget</header>
</customwidget>
<customwidget>
<class>BECQueue</class>
<extends>QTableWidget</extends>
<header>bec_queue</header>
</customwidget>
<customwidget>
<class>ScanControl</class>
<extends>QWidget</extends>
<header>scan_control</header>
</customwidget>
<customwidget>
<class>VSCodeEditor</class>
<extends>WebsiteWidget</extends>
<header>vs_code_editor</header>
</customwidget>
<customwidget>
<class>BECStatusBox</class>
<extends>QWidget</extends>
<header>bec_status_box</header>
</customwidget>
<customwidget>
<class>BECDockArea</class>
<extends>QWidget</extends>
<header>dock_area</header>
</customwidget>
<customwidget>
<class>QWebEngineView</class>
<extends></extends>
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -1,10 +1,22 @@
import os
from typing import TYPE_CHECKING
from qtpy.QtGui import QActionGroup, QAction
from qtpy.QtWidgets import QStyle
from bec_lib.logger import bec_logger
from qtpy.QtWidgets import QApplication, QMainWindow
from bec_widgets.cli.rpc.rpc_register import RPCRegister
from bec_widgets.utils import UILoader
from bec_widgets.utils.bec_qapp import BECApplication
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.colors import apply_theme
from bec_widgets.utils.container_utils import WidgetContainerUtils
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
from bec_widgets.widgets.containers.main_window.addons.web_links import BECWebLinksMixin
if TYPE_CHECKING:
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
logger = bec_logger.logger
@ -14,6 +26,102 @@ class BECMainWindow(BECWidget, QMainWindow):
BECWidget.__init__(self, gui_id=gui_id, **kwargs)
QMainWindow.__init__(self, *args, **kwargs)
self.app = QApplication.instance()
# self._upgrade_qapp() #TODO consider to make upgrade function to any QApplication to BECQApplication
self._init_ui()
def _init_ui(self):
# Set the window title
self.setWindowTitle("BEC")
# Set Menu and Status bar
self._setup_menu_bar()
# BEC Specific UI
self._init_bec_specific_ui()
# self.ui = UILoader
# ui_file_path = os.path.join(os.path.dirname(__file__), "general_app.ui")
# self.load_ui(ui_file_path)
# TODO can be implemented for toolbar
def load_ui(self, ui_file):
loader = UILoader(self)
self.ui = loader.loader(ui_file)
self.setCentralWidget(self.ui)
def _init_bec_specific_ui(self):
if isinstance(self.app, BECApplication):
self.statusBar().showMessage(f"App ID: {self.app.gui_id}")
else:
logger.warning(
"Application is not a BECApplication instance. Status bar will not show App ID. Please initialize the application with BECApplication."
)
def list_app_hierarchy(self):
"""
List the hierarchy of the application.
"""
self.app.list_hierarchy()
def _setup_menu_bar(self):
"""
Setup the menu bar for the main window.
"""
menu_bar = self.menuBar()
########################################
# Theme menu
theme_menu = menu_bar.addMenu("Theme")
theme_group = QActionGroup(self)
light_theme_action = QAction("Light Theme", self, checkable=True)
dark_theme_action = QAction("Dark Theme", self, checkable=True)
theme_group.addAction(light_theme_action)
theme_group.addAction(dark_theme_action)
theme_group.setExclusive(True)
theme_menu.addAction(light_theme_action)
theme_menu.addAction(dark_theme_action)
# Connect theme actions
light_theme_action.triggered.connect(lambda: self.change_theme("light"))
dark_theme_action.triggered.connect(lambda: self.change_theme("dark"))
# Set the default theme
# TODO can be fetched from app
dark_theme_action.setChecked(True)
########################################
# Help menu
help_menu = menu_bar.addMenu("Help")
help_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion)
bug_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxInformation)
bec_docs = QAction("BEC Docs", self)
bec_docs.setIcon(help_icon)
widgets_docs = QAction("BEC Widgets Docs", self)
widgets_docs.setIcon(help_icon)
bug_report = QAction("Bug Report", self)
bug_report.setIcon(bug_icon)
bec_docs.triggered.connect(BECWebLinksMixin.open_bec_docs)
widgets_docs.triggered.connect(BECWebLinksMixin.open_bec_widgets_docs)
bug_report.triggered.connect(BECWebLinksMixin.open_bec_bug_report)
help_menu.addAction(bec_docs)
help_menu.addAction(widgets_docs)
help_menu.addAction(bug_report)
debug_bar = menu_bar.addMenu("DEBUG")
list_hierarchy = QAction("List App Hierarchy", self)
list_hierarchy.triggered.connect(self.list_app_hierarchy)
debug_bar.addAction(list_hierarchy)
def change_theme(self, theme):
apply_theme(theme)
def _dump(self):
"""Return a dictionary with informations about the application state, for use in tests"""
# TODO: ModularToolBar and something else leak top-level widgets (3 or 4 QMenu + 2 QWidget);
@ -40,7 +148,7 @@ class BECMainWindow(BECWidget, QMainWindow):
def new_dock_area(
self, name: str | None = None, geometry: tuple[int, int, int, int] | None = None
) -> BECDockArea:
) -> "BECDockArea":
"""Create a new dock area.
Args:
@ -49,6 +157,8 @@ class BECMainWindow(BECWidget, QMainWindow):
Returns:
BECDockArea: The newly created dock area.
"""
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
with RPCRegister.delayed_broadcast() as rpc_register:
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(BECDockArea)
if name is not None:
@ -72,3 +182,68 @@ class BECMainWindow(BECWidget, QMainWindow):
def cleanup(self):
super().close()
class WindowWithUi(BECMainWindow):
"""
This is just testing app wiht UI file which could be connected to RPC.
"""
USER_ACCESS = [
"new_dock_area",
"all_connections",
"change_theme",
"dock_area",
"register_all_rpc",
"widget_list",
"list_app_hierarchy",
]
def __init__(self, *args, name: str = None, **kwargs):
super().__init__(*args, **kwargs)
if name is None:
name = self.__class__.__name__
else:
if not WidgetContainerUtils.has_name_valid_chars(name):
raise ValueError(f"Name {name} contains invalid characters.")
self._name = name if name else self.__class__.__name__
ui_file_path = os.path.join(os.path.dirname(__file__), "example_app.ui")
self.load_ui(ui_file_path)
def load_ui(self, ui_file):
loader = UILoader(self)
self.ui = loader.loader(ui_file)
self.setCentralWidget(self.ui)
# TODO actually these propertiers are not much exposed now in the real CLI
@property
def dock_area(self):
dock_area = self.ui.dock_area
return dock_area
@property
def all_connections(self) -> list:
all_connections = self.rpc_register.list_all_connections()
all_connections_keys = list(all_connections.keys())
return all_connections_keys
def register_all_rpc(self):
app = QApplication.instance()
app.register_all()
@property
def widget_list(self) -> list:
"""Return a list of all widgets in the application."""
app = QApplication.instance()
all_widgets = app.list_all_bec_widgets()
return all_widgets
if __name__ == "__main__":
import sys
app = BECApplication(sys.argv)
main_window = WindowWithUi()
main_window.show()
sys.exit(app.exec())

View File

@ -18,6 +18,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.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
from bec_widgets.widgets.plots.waveform.curve import Curve, CurveConfig, DeviceSignal
@ -1581,7 +1582,7 @@ class Waveform(PlotBase):
super().cleanup()
class DemoApp(QMainWindow): # pragma: no cover
class DemoApp(BECMainWindow): # pragma: no cover
def __init__(self):
super().__init__()
self.setWindowTitle("Waveform Demo")
@ -1604,9 +1605,9 @@ class DemoApp(QMainWindow): # pragma: no cover
if __name__ == "__main__": # pragma: no cover
import sys
from qtpy.QtWidgets import QApplication
from bec_widgets.utils.bec_qapp import BECApplication
app = QApplication(sys.argv)
app = BECApplication(sys.argv)
set_theme("dark")
widget = DemoApp()
widget.show()