3. BaseMalWidget
The BaseMalWidget class
is a reusable (QWidget, Logger) base class that centralizes the MAL
connection boilerplate shared by all widgets in the IFW Widget Library.
Instead of each widget manually creating facades, wiring connection signals,
and clearing Taurus bgRole, BaseMalWidget handles all of this
automatically.
Every CCF widget, SysSup widget, and custom widget in the library inherits
from BaseMalWidget.
3.1. What It Provides
BaseMalWidget handles six areas of boilerplate:
- ConnectionManager
Creates the singleton
ConnectionManageron construction and stores it asself._conn_mgr, so subclasses can obtain facades without instantiating their own manager.- Facade Registration
Subclasses override
_setup_facades()to obtain facades fromself._conn_mgrand callself.register_facade(facade)for each one. This automatically wires the facade’sconnectionChangedsignal.- Connection Monitoring
All registered facades are monitored. When any facade disconnects, the widget is automatically disabled (visually grayed out), providing immediate feedback to the user.
- Taurus Status Listener Factory
make_status_listener()creates aQObjectTaurusListenerfor an OLDB data point, with automatic existence checking. Returns(Attribute, listener)or(None, None)if the path does not exist.- TaurusLabel bgRole Clearing
remove_bgrole()usesfindChildrento discover allTaurusBaseWidgetdescendants (TaurusLabel,TaurusState,TimeHMSWidget, etc.) and clears theirbgRoleattribute so that QSS themes control appearance uniformly.- Logger Mixin
Inherits
Loggerfrom taurus, providingself.debug(),self.info(),self.warning(), andself.error()methods.
3.2. Using BaseMalWidget
To create a widget that inherits from BaseMalWidget, follow this pattern:
Call
super().__init__(parent, base_uri)Store constructor parameters (
dcs_db_prefix, etc.)Call
self._setup_facades()to register facadesInstantiate the OLDB paths dataclass
Set up the UI
Call
self.remove_bgrole()Call
_update_db_models()to bind Taurus labelsCall
_init_gui()to wire up Qt signals
Example:
from dataclasses import dataclass
from taurus.external.qt.QtGui import QWidget
from taurus.external.qt.QtCore import Slot
from ifw.wdglib.comm import StdCmdsFacade
from ifw.wdglib.widgets.common import BaseMalWidget
from myapp.ui_mystatewidget import Ui_MyStateWidget
@dataclass(frozen=True)
class MyStateOldbPaths:
dcs_db_prefix: str
@property
def state_path(self) -> str:
return f"{self.dcs_db_prefix}/sm/state"
class MyStateWidget(BaseMalWidget):
"""Widget displaying a subsystem state value with state commands."""
def __init__(
self,
parent: QWidget,
base_uri: str,
dcs_db_prefix: str,
) -> None:
super().__init__(parent, base_uri)
self._dcs_db_prefix = dcs_db_prefix
self._setup_facades()
self.oldb_paths = MyStateOldbPaths(dcs_db_prefix)
self.ui = Ui_MyStateWidget()
self.ui.setupUi(self)
self.remove_bgrole()
self._update_db_models()
self._init_gui()
def _setup_facades(self) -> None:
self._stdcmds = self._conn_mgr.get_stdcmds(
f"{self._base_uri}/StdCmds"
)
self.register_facade(self._stdcmds)
def _update_db_models(self) -> None:
self.ui.stateLabel.setModel(self.oldb_paths.state_path)
def _init_gui(self) -> None:
self.ui.stateComboBox.addItems(["Init", "Enable", "Disable"])
self.ui.stateComboBox.currentIndexChanged.connect(
self._on_stateComboBox_currentIndexChanged
)
self._update_connection()
@Slot(str)
def _on_stateComboBox_currentIndexChanged(self, new_state) -> None:
selection = self.ui.stateComboBox.currentText()
if selection == "Init":
self._stdcmds.init()
elif selection == "Enable":
self._stdcmds.enable()
elif selection == "Disable":
self._stdcmds.disable()
3.3. Method Reference
- __init__(parent, base_uri)
Initializes the widget, creates the
ConnectionManagersingleton, storesbase_uri, and initializes an empty facade list.- Args:
parent: Parent QWidget. base_uri: MAL base URI, e.g. “zpb.rr://127.0.0.1:12091”.
- _setup_facades()
Override in subclass to register the MAL facades this widget needs. Raise
NotImplementedErrorif not overridden.After obtaining each facade from
self._conn_mgr, callself.register_facade(facade)to wire itsconnectionChangedsignal. Available factory methods:get_stdcmds(uri)– Standard lifecycle commandsget_dcscmds(uri)– Device control/monitoringget_reccmds(uri)– Recording commandsget_fcfcmds(uri)– FCF I/O device commandsget_syssupcmds(uri)– System supervisor
- register_facade(facade)
Connects the facade’s
connectionChangedsignal toon_cmds_connection_changedand adds it to the internal list of facades checked by_update_connection().- on_cmds_connection_changed(state)
Slot connected to all registered facade
connectionChangedsignals. Delegates to_update_connection(). Override if you need per-facade behavior (e.g., individual connection LEDs).- _update_connection()
Enables or disables the widget based on whether ALL registered facades are connected. Override for custom behavior (e.g., per-facade status indicators, or enabling the widget if only a subset of facades is required).
- make_status_listener(full_attr_path, event, name)
Creates a
QObjectTaurusListenerfor an OLDB data point. Checks that the data point exists before creating the listener. Returns(Attribute, QObjectTaurusListener)or(None, None)on error.- Args:
full_attr_path: Full OLDB path to listen to. event: Callable connected to the listener’s
taurusEventsignal. name: Name for the QObjectTaurusListener instance.
- remove_bgrole()
Clears the
bgRoleattribute on allTaurusBaseWidgetdescendants (TaurusLabel,TaurusState,TimeHMSWidget, etc.) usingfindChildren. Must be called afterui.setupUi(self)so that the widget hierarchy exists.
3.4. See Also
For a complete step-by-step walkthrough of creating a custom widget using
BaseMalWidget, see the Creating a Custom Widget
chapter.