The Graphical Interface¶
The GUI is built with PyQt6 (through qtpy
for cross-toolkit compatibility) and reuses PyMeasure's managed-window machinery.
It lives in laser_setup/display/. There are three windows and a handful of
reusable widgets, all driven by CONFIG.Qt.
Entry point: display_window()¶
display/app.py:display_window(procedure=None) is the single GUI entry point.
It:
- creates the
QApplicationsingleton, - shows the splash screen,
- applies the configured style, palette (dark mode) and font from
CONFIG.Qt.GUI, - installs a global
ShortcutFilterfor keyboard shortcuts, and - opens either the MainWindow (no procedure) or an ExperimentWindow (a procedure class/instance).
| Shortcut | Action |
|---|---|
| Ctrl+W | Close the current window |
| Ctrl++ / Ctrl+- | Zoom in / out |
| F11 | Toggle maximize |
Main Window¶
display/windows/main_window.py is the hub. Its menu bar is generated entirely
from configuration:
| Menu | Built from | Opens |
|---|---|---|
| Procedures | CONFIG.procedures._types |
an ExperimentWindow (Ctrl+1, Ctrl+2 …) |
| Sequences | CONFIG.sequences._types |
a SequenceWindow (Ctrl+Shift+1 …) |
| Scripts | CONFIG.scripts |
runs a function (Alt+1 …) |
| View | — | database browser, camera, terminal, logs |
| Config | — | edit / import / export configuration |
| Help | CONFIG.instruments |
per-instrument docstrings |
It also shows the project README in the central panel and a status bar with
a red Reload button (Ctrl+R) that becomes active when configuration
changes. A background Worker thread polls a status message periodically.
Why a Reload button?
CONFIG is read once at startup. Editing config (in a file or via the
Config editor) requires a reload to rebuild it, which restarts the window.
Experiment Window¶
display/windows/experiment_window.py subclasses PyMeasure's
ManagedWindowBase and runs one procedure with live visualization.
On construction it validates that the procedure has at least two
DATA_COLUMNS (the first two become the default x/y axes) and builds:
- a Plot widget (x vs y, with axis selectors),
- a Dock of stacked plots (
Qt.ExperimentWindow.dock_plot_number), - a Log widget capturing the run's log records,
- a Text/Info widget rendering
Qt.ExperimentWindow.info_file(Markdown).
When you press Queue:
- a
Resultsobject is created with a unique filename (see Data & Output Files), - the procedure's
patch_parameters()hook runs, - PyMeasure's manager runs
startup() → execute() → shutdown()in a background thread, streamingemit('results', …)to the plots andemit('progress', …)to the progress bar.
Procedures derived from BaseProcedure also get a Shutdown button that calls
instruments.shutdown_all() for a safe power-down.
Dark-mode plots
In dark mode the plot backgrounds are set to black explicitly, because pyqtgraph defaults to a white canvas (which would hide light-colored curves).
Sequence Window¶
display/windows/sequence_window.py runs a chain of procedures. It reads a
Sequence class (.procedures, .common_procedure, .inputs_ignored) and
builds:
- a common-parameter panel (inputs shared by all steps), and
- a column per step with its unique inputs, a color-coded status icon, and
two timers (time-in-step
+and cumulative=).
Queue runs each step in order using a blocking event loop (the window stays
responsive to abort but processes steps sequentially). On failure it shows an
abort dialog with a countdown (Qt.SequenceWindow.abort_timeout). Instruments
are shut down after the final step. See Sequences.
Widgets¶
display/widgets/ provides the reusable pieces:
| Widget | Role |
|---|---|
InputsWidget |
Parameter input form (wraps PyMeasure's, accepts a class or instance). |
LogWidget / LogsWidget |
Live, colorized log capture. |
TextWidget |
Read-only Markdown/text viewer (the Info tab, README). |
SQLiteWidget |
Browse the parameters database in a sortable table. |
ConfigWidget |
Edit CONFIG as a parameter tree and save back to YAML. |
CameraWidget |
Live camera feed (OpenCV) — e.g. to watch the sample/laser spot. |
Threading model¶
- PyMeasure's manager runs each procedure in its own background thread, so the GUI stays responsive during a measurement.
- The
Workerhelper (display/Qt.py) runs short background tasks (camera scanning, status polling) on aQThreadand signals completion. - The SequenceWindow intentionally drives steps from a blocking event loop so it can monitor them one at a time.
Configuration cheat-sheet¶
All window behavior is under CONFIG.Qt:
Qt:
GUI: {style, dark_mode, font, font_size, splash_image}
MainWindow: {title, readme_file, size, widget_size, icon}
ExperimentWindow: {title, inputs_in_scrollarea, dock_plot_number, info_file, icon}
SequenceWindow: {abort_timeout}
See the Configuration reference for defaults.