Repository navigation
Module Registry and UI Layout
Relevant source files
The following files were used as context for generating this wiki page:
- main_gui.py
- src/assets/lang/en.json
- src/assets/lang/ja.json
- src/core/module_constants.py
- src/gui/main_window.py
- src/gui/startup.py
- src/gui/widgets/bnim_meter.py
- src/gui/widgets/detachable_wrapper.py
- src/gui/widgets/log_viewer.py
- src/gui/widgets/raw_time_series.py
- src/gui/widgets/sound_level_meter.py
- tests/logic_verification/gui/test_compact_modes.py
- tests/logic_verification/gui/test_lufs_meter_compact.py
This page describes the structural foundation of the MeasureLab interface, focusing on how modules are registered, dynamically loaded, and managed within the main application window.
MeasureLab utilizes a centralized registry to manage the vast collection of measurement instruments. This registry decouples the module definitions from the main window logic, allowing for easy extension and maintenance.
The MODULE_REGISTRY is a dictionary located in src/gui/main_window.py src/gui/main_window.py:74-116. It maps a unique string key (defined in module_constants.py) to a tuple containing the filesystem path and the class name of the widget.
| Component | File Reference | Role |
|---|---|---|
| Module Keys | src/core/module_constants.py |
Unique identifiers like MODULE_SPECTRUM_ANALYZER. |
| Registry Map | src/gui/main_window.py |
Maps keys to ("module.path", "ClassName"). |
| Loader | src/gui/main_window.py |
_load_module_class(module_key) performs dynamic imports. |
To minimize startup time and memory footprint, MeasureLab employs a lazy-loading strategy. Heavy dependencies (such as scipy, matplotlib, or pyfftw) are only imported when a specific module is selected by the user src/gui/main_window.py:125-135.
-
Startup: Only core logic and the
MainWindowshell are loaded. -
Selection: When a user clicks a sidebar item,
_load_module_classusesimportlib.import_moduleto bring the specific widget into memorysrc/gui/main_window.py:119-122. -
PyInstaller Note: Because dynamic imports are invisible to static analysis, explicit imports are maintained in
src/gui/pyinstaller_imports.pyto ensure all modules are bundled in the compiled executablesrc/gui/main_window.py:129-130.
Sources: src/gui/main_window.py:74-135, src/core/module_constants.py:1-91
The MainWindow src/gui/main_window.py:151 follows a standard sidebar-content pattern, managed by a QStackedWidget.
The interface is divided into three primary zones:
-
Sidebar (
QListWidget): Displays the list of available modules defined inALL_MODULE_KEYSsrc/gui/main_window.py:270-275. -
Content Area (
QStackedWidget): Holds the active module widget. Only one module is visible at a time to conserve GPU resourcessrc/gui/main_window.py:284. -
Status Bar: Displays real-time engine stats like sample rate, CPU load, and peak levels
src/gui/main_window.py:330-335.
The following diagram illustrates how selecting a module in the sidebar triggers the instantiation and display of the measurement widget.
Sidebar Selection to Widget Display
sequenceDiagram
participant U as User
participant S as Sidebar (QListWidget)
participant MW as MainWindow
participant R as MODULE_REGISTRY
participant SW as QStackedWidget
U->>S: Clicks "Sound Level Meter"
S->>MW: itemClicked(item)
MW->>MW: _on_module_selected(key)
alt Widget not in cache
MW->>R: Lookup "Sound Level Meter"
R-->>MW: ("src.gui.widgets.sound_level_meter", "SoundLevelMeter")
MW->>MW: _load_module_class(key)
MW->>MW: Instantiate SoundLevelMeter(audio_engine)
MW->>SW: addWidget(DetachableWidgetWrapper)
end
MW->>SW: setCurrentWidget(wrapper)
Sources: src/gui/main_window.py:265-310, src/gui/main_window.py:464-500
Every module in MeasureLab is wrapped in a DetachableWidgetWrapper src/gui/widgets/detachable_wrapper.py:93. This component provides a standardized header and utility functions for all instruments.
-
Window Detachment: Users can pop a module out into an
IndependentWindowsrc/gui/widgets/detachable_wrapper.py:24. This is useful for multi-monitor setups. -
Compact Mode: Implements
CompactableWidgetInterface. When enabled, it hides non-essential controls and sidebars to focus purely on the visualizationsrc/gui/widgets/detachable_wrapper.py:158-164. -
Standard Utilities: Provides buttons for "Screenshot", "Logs", and "Send to Comparer"
src/gui/widgets/detachable_wrapper.py:145-170.
graph TD
subgraph "MainWindow (QStackedWidget)"
W["DetachableWidgetWrapper"]
end
subgraph "DetachableWidgetWrapper"
H["Header (Title, Detach, Screenshot)"]
C["Content Container"]
end
subgraph "Module Implementation"
M["MeasurementModule (e.g., SpectrumAnalyzer)"]
end
W --> H
W --> C
C --> M
Sources: src/gui/widgets/detachable_wrapper.py:93-189, tests/logic_verification/gui/test_compact_modes.py:155-184
The MainWindow manages the global application state and coordinates between the UI and the AudioEngine.
-
Environment Setup:
main_gui.pyconfigures high DPI scaling and loggingmain_gui.py:15-33. -
Splash Screen: A
WrappingSplashScreenis shown immediately while the main window initializesmain_gui.py:152-183. -
Engine Attachment: The
MainWindowreceives the singletonAudioEngineinstance and connects it to the status bar for real-time monitoringsrc/gui/main_window.py:163-175.
The MainWindow ensures that only one module is "Active" at a time to prevent audio callback collisions.
-
Activation: When a module is selected, the
MainWindowcallsstart_analysis()on the modulesrc/gui/main_window.py:530. -
Deactivation: When switching away, the
MainWindowcallsstop_analysis()to unregister audio callbacks and free DSP resourcessrc/gui/main_window.py:510-520. -
Cleanup: On application close,
MainWindowiterates through all cached modules to ensure every background thread and audio stream is terminated safelysrc/gui/main_window.py:410-430.
Sources: main_gui.py:135-200, src/gui/main_window.py:151-220, src/gui/main_window.py:502-540