0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 11:41:49 +02:00

WIP Demo waveform plugin with json curves

This commit is contained in:
2025-01-13 13:43:54 +01:00
parent f219c6fb57
commit f4202427ad
5 changed files with 225 additions and 0 deletions

View File

@ -0,0 +1,15 @@
def main(): # pragma: no cover
from qtpy import PYSIDE6
if not PYSIDE6:
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
return
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
from bec_widgets.widgets.plots_next_gen.waveform.waveform_plot_plugin import WaveformPlotPlugin
QPyDesignerCustomWidgetCollection.addCustomWidget(WaveformPlotPlugin())
if __name__ == "__main__": # pragma: no cover
main()

View File

@ -0,0 +1,138 @@
from __future__ import annotations
import json
from typing import Optional
import pyqtgraph as pg
from qtpy.QtCore import Property, Signal
from qtpy.QtWidgets import QApplication, QWidget, QVBoxLayout
from bec_widgets.utils.bec_widget import BECWidget
##############################################################################
# MinimalPlotBase (a stand-in for your real PlotBase)
##############################################################################
class MinimalPlotBase(QWidget):
"""
A trivial container that just holds a single pyqtgraph PlotWidget.
In your actual code, replace this with your real 'PlotBase' class.
"""
def __init__(self, parent=None):
super().__init__(parent)
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
self.plot_item = pg.PlotItem()
self.plot_widget = pg.PlotWidget(plotItem=self.plot_item)
layout.addWidget(self.plot_widget)
self.plot_item.addLegend()
##############################################################################
# WaveformPlot subclass that uses a QProperty for multiple curve definitions
##############################################################################
class WaveformPlot(BECWidget, MinimalPlotBase):
"""
Demonstrates a 'curvesJson' QProperty that holds an array of curve definitions.
Each array entry might look like:
{
"label": "MyCurve",
"color": "#ff0000"
// optionally: "device": "devA", "signal": "sigB", ...
}
On setting 'curvesJson', the widget parses the JSON, clears old curves,
and creates new PlotDataItems with dummy data (for demonstration).
"""
PLUGIN = True
# Signal to notify when any property changes (optional convenience signal)
property_changed = Signal(str, object)
# We'll store our JSON string in this private attribute
_curves_json: str = ""
def __init__(self, parent: Optional[QWidget] = None):
super().__init__()
MinimalPlotBase.__init__(self, parent=parent)
# Keep track of the PlotDataItem objects so we can remove them on update
self._waveform_curves = []
# ------------------------------------------------------------------------
# QProperty: curvesJson
# ------------------------------------------------------------------------
def getCurvesJson(self) -> str:
"""Return the JSON string describing all curves."""
return self._curves_json
def setCurvesJson(self, new_json: str):
"""Set a new JSON definition for the curves; parse and rebuild them."""
if self._curves_json != new_json:
self._curves_json = new_json
# Emit a signal if you like
self.property_changed.emit("curvesJson", new_json)
# Rebuild the curves
self._build_curves_from_json(new_json)
# The actual QProperty for Designer (or QSettings) to see
curvesJson = Property(str, fget=getCurvesJson, fset=setCurvesJson)
# ------------------------------------------------------------------------
# Build or rebuild the curves from the JSON definition
# ------------------------------------------------------------------------
def _build_curves_from_json(self, json_str: str):
"""
Clears out any existing PlotDataItems,
then parses the JSON and creates new items.
Here we just do dummy data to show them visually.
"""
# 1. Remove old items
for c in self._waveform_curves:
self.plot_item.removeItem(c)
self._waveform_curves.clear()
# 2. Parse the JSON
try:
curve_defs = json.loads(json_str)
if not isinstance(curve_defs, list):
raise ValueError("curvesJson must be a JSON list of objects.")
except Exception as e:
print(f"[WaveformPlot] Error parsing curvesJson: {e}")
return
# 3. Create new PlotDataItems for each definition
for idx, cdef in enumerate(curve_defs):
label = cdef.get("label", f"Curve{idx + 1}")
color = cdef.get("color", "blue")
# In your real code, you might also parse "device", "signal", etc.
# Dummy data (just to show distinct lines)
xdata = [0, 1, 2, 3, 4]
ybase = idx * 3
ydata = [ybase + 0, ybase + 1, ybase + 2, ybase + 1, ybase + 0]
curve_item = pg.PlotDataItem(xdata, ydata, pen=color, name=label)
self.plot_item.addItem(curve_item)
self._waveform_curves.append(curve_item)
##############################################################################
# Standalone test
##############################################################################
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
widget = WaveformPlot()
widget.setWindowTitle("Minimal multiple-curves example with QProperty + PlotBase-like class")
# Example JSON: two curves with different color/labels
example_json = json.dumps(
[{"label": "Alpha", "color": "red"}, {"label": "Beta", "color": "#00ff00"}]
)
widget.curvesJson = example_json
widget.show()
sys.exit(app.exec_())

View File

@ -0,0 +1 @@
{'files': ['waveform_demo.py']}

View File

@ -0,0 +1,71 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
from bec_widgets.utils.bec_designer import designer_material_icon
from bec_widgets.widgets.plots_next_gen.waveform.waveform_demo import WaveformPlot
class WaveformPlotPlugin(QDesignerCustomWidgetInterface):
"""
Minimal custom widget plugin for Qt Designer.
- Creates WaveformPlot
- Provides DOM XML
- Installs our TaskMenu extension factory
"""
def __init__(self):
super().__init__()
self._initialized = False
self._extension_factory = None
def initialize(self, form_editor):
if self._initialized:
return
self._initialized = True
# Register our task menu extension factory with the form editor
manager = form_editor.extensionManager()
if manager:
factory = WaveformPlotTaskMenuFactory(manager)
manager.registerExtensions(factory, "org.qt-project.Qt.Designer.TaskMenu")
def isInitialized(self):
return self._initialized
def createWidget(self, parent):
return WaveformPlot(parent)
def name(self):
return "WaveformPlot"
def group(self):
return "MyPlotWidgets"
def toolTip(self):
return "WaveformPlot with multiple curves"
def whatsThis(self):
return self.toolTip()
def includeFile(self):
# Typically the python module name where WaveformPlot is defined
# (used in the generated ui code)
return __name__
def icon(self):
# Provide an icon if desired
# e.g. QIcon(":/icons/waveform.png")
return None
def isContainer(self):
return False
def domXml(self):
return """
<ui language='c++'>
<widget class='WaveformPlot' name='waveformPlot'>
</widget>
</ui>
"""