diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf13fa8..7729fcd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+### Version 0.0.4 (05-05-2024)
+- Added display of multiple measurements that can be displayed in th plot window.
+- Now using the FileManager class instead of QFileManager
+
### Version 0.0.3 (26-04-2024)
- Switched to new formbuilder. This should make implementation of signal processing methods more robust and easier.
diff --git a/pyproject.toml b/pyproject.toml
index 1e965e4..5ea2dd9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,7 @@ allow-direct-references = true
[project]
name = "nqrduck-measurement"
-version = "0.0.3"
+version = "0.0.4"
authors = [
{ name="jupfi", email="support@nqrduck.cool" },
]
diff --git a/src/nqrduck_measurement/controller.py b/src/nqrduck_measurement/controller.py
index 0968fc2..7b26994 100644
--- a/src/nqrduck_measurement/controller.py
+++ b/src/nqrduck_measurement/controller.py
@@ -230,3 +230,43 @@ class MeasurementController(ModuleController):
self.module.model.displayed_measurement = apodized_measurement
self.module.model.add_measurement(apodized_measurement)
+
+ @pyqtSlot()
+ def change_displayed_measurement(self, measurement=None) -> None:
+ """Change the displayed measurement."""
+
+ if not self.module.model.measurements:
+ logger.debug("No measurements to display.")
+ return
+
+ if not measurement:
+ index = self.module.view._ui_form.selectionBox.value()
+ self.module.model.displayed_measurement = self.module.model.measurements[
+ index
+ ]
+ logger.debug(
+ f"Changing displayed measurement to {self.module.model.displayed_measurement.name}."
+ )
+ else:
+ logger.debug(f"Changing displayed measurement to {measurement.name}.")
+ self.module.model.displayed_measurement = measurement
+
+ @pyqtSlot(Measurement)
+ def delete_measurement(self, measurement: Measurement) -> None:
+ """Delete a measurement.
+
+ The measurement is removed from the list of measurements. Then the displayed measurement is updated.
+
+ Args:
+ measurement (Measurement): The measurement to delete.
+ """
+ logger.debug("Deleting measurement.")
+ self.module.model.remove_measurement(measurement)
+
+ if measurement == self.module.model.displayed_measurement:
+ if self.module.model.measurements:
+ self.module.model.displayed_measurement = (
+ self.module.model.measurements[-1]
+ )
+ else:
+ self.module.model.displayed_measurement = None
diff --git a/src/nqrduck_measurement/model.py b/src/nqrduck_measurement/model.py
index efa8e2c..871a99b 100644
--- a/src/nqrduck_measurement/model.py
+++ b/src/nqrduck_measurement/model.py
@@ -50,6 +50,7 @@ class MeasurementModel(ModuleModel):
displayed_measurement_changed = pyqtSignal(Measurement)
measurements_changed = pyqtSignal(list)
+
view_mode_changed = pyqtSignal(str)
measurement_frequency_changed = pyqtSignal(float)
@@ -94,6 +95,14 @@ class MeasurementModel(ModuleModel):
def add_measurement(self, measurement: Measurement):
"""Add a measurement to the list of measurements."""
self.measurements.append(measurement)
+ # Change the maximum value of the selectionBox.
+ self.measurements_changed.emit(self.measurements)
+ self.displayed_measurement_changed.emit(measurement)
+
+ def remove_measurement(self, measurement : Measurement):
+ """Remove a measurement from the list of measurements."""
+ self.measurements.remove(measurement)
+ # Change the maximum value of the selectionBox.
self.measurements_changed.emit(self.measurements)
@property
@@ -108,7 +117,12 @@ class MeasurementModel(ModuleModel):
@displayed_measurement.setter
def displayed_measurement(self, value: Measurement):
self._displayed_measurement = value
- self.displayed_measurement_changed.emit(value)
+ if value is not None:
+ logger.debug("Displayed measurement: " + value.name)
+ self.displayed_measurement_changed.emit(value)
+ else:
+ self.module.view.update_displayed_measurement()
+
@property
def measurement_frequency(self):
diff --git a/src/nqrduck_measurement/resources/measurement_widget.ui b/src/nqrduck_measurement/resources/measurement_widget.ui
index 005ea13..fa101a2 100644
--- a/src/nqrduck_measurement/resources/measurement_widget.ui
+++ b/src/nqrduck_measurement/resources/measurement_widget.ui
@@ -6,7 +6,7 @@
0
0
- 1920
+ 1807
1080
@@ -23,7 +23,7 @@
-
-
-
+
-
@@ -150,6 +150,22 @@
+ -
+
+
+
+ 75
+ true
+
+
+
+ Measurements:
+
+
+
+ -
+
+
-
@@ -184,7 +200,7 @@
-
-
+
-
@@ -195,6 +211,9 @@
+ -
+
+
-
-
diff --git a/src/nqrduck_measurement/view.py b/src/nqrduck_measurement/view.py
index 74ac994..5c1dcf6 100644
--- a/src/nqrduck_measurement/view.py
+++ b/src/nqrduck_measurement/view.py
@@ -2,7 +2,19 @@
import logging
import numpy as np
-from PyQt6.QtWidgets import QWidget, QDialog, QLabel, QVBoxLayout
+from functools import partial
+from PyQt6.QtWidgets import (
+ QWidget,
+ QDialog,
+ QLabel,
+ QVBoxLayout,
+ QHBoxLayout,
+ QPushButton,
+ QListWidgetItem,
+ QSizePolicy,
+ QApplication,
+)
+from PyQt6.QtGui import QFontMetrics
from PyQt6.QtCore import pyqtSlot, Qt
from nqrduck.module.module_view import ModuleView
from nqrduck.assets.icons import Logos
@@ -50,6 +62,8 @@ class MeasurementView(ModuleView):
)
self.module.model.view_mode_changed.connect(self.update_displayed_measurement)
+ self.module.model.measurements_changed.connect(self.on_measurements_changed)
+
self._ui_form.buttonStart.clicked.connect(
self.on_measurement_start_button_clicked
)
@@ -105,6 +119,11 @@ class MeasurementView(ModuleView):
self._ui_form.averagesEdit.set_min_value(1)
self._ui_form.averagesEdit.set_max_value(1e6)
+ # Connect selectionBox signal fors switching the displayed measurement
+ self._ui_form.selectionBox.valueChanged.connect(
+ self.module.controller.change_displayed_measurement
+ )
+
def init_plotter(self) -> None:
"""Initialize plotter with the according units for time domain."""
plotter = self._ui_form.plotter
@@ -143,6 +162,18 @@ class MeasurementView(ModuleView):
plotter = self._ui_form.plotter
plotter.canvas.ax.clear()
try:
+ if self.module.model.displayed_measurement is None:
+ logger.debug("No measurement data to display. Clearing plotter.")
+
+ if self.module.model.view_mode == self.module.model.FFT_VIEW:
+ self.change_to_fft_view()
+ else:
+ self.change_to_time_view()
+
+ self._ui_form.plotter.canvas.draw()
+
+ return
+
if self.module.model.view_mode == self.module.model.FFT_VIEW:
self.change_to_fft_view()
y = self.module.model.displayed_measurement.fdy
@@ -173,6 +204,26 @@ class MeasurementView(ModuleView):
# Add legend
self._ui_form.plotter.canvas.ax.legend()
+ # Highlight the displayed measurement in the measurementsList
+ for i in range(self._ui_form.measurementsList.count()):
+ item = self._ui_form.measurementsList.item(i)
+ widget = self._ui_form.measurementsList.itemWidget(item)
+ button = widget.layout().itemAt(0).widget()
+ # Get the measurement by accessing measurement property
+ measurement = button.property("measurement")
+ if measurement == self.module.model.displayed_measurement:
+ item.setSelected(True)
+ else:
+ item.setSelected(False)
+
+ # Update the number of the selectionBox
+ for measurement in self.module.model.measurements:
+ if measurement.name == self.module.model.displayed_measurement.name:
+ self._ui_form.selectionBox.setValue(
+ self.module.model.measurements.index(measurement)
+ )
+ break
+
except AttributeError:
logger.debug("No measurement data to display.")
self._ui_form.plotter.canvas.draw()
@@ -200,7 +251,7 @@ class MeasurementView(ModuleView):
"""Slot for when the measurement save button is clicked."""
logger.debug("Measurement save button clicked.")
- file_manager = self.QFileManager(
+ file_manager = self.FileManager(
self.module.model.FILE_EXTENSION, parent=self.widget
)
file_name = file_manager.saveFileDialog()
@@ -212,13 +263,84 @@ class MeasurementView(ModuleView):
"""Slot for when the measurement load button is clicked."""
logger.debug("Measurement load button clicked.")
- file_manager = self.QFileManager(
+ file_manager = self.FileManager(
self.module.model.FILE_EXTENSION, parent=self.widget
)
file_name = file_manager.loadFileDialog()
if file_name:
self.module.controller.load_measurement(file_name)
+ @pyqtSlot()
+ def on_measurements_changed(self) -> None:
+ """Slot for when a measurement is added."""
+ logger.debug("Measurement changed.")
+
+ if len(self.module.model.measurements) == 0:
+ self.module.view._ui_form.selectionBox.setMaximum(0)
+ self.module.view._ui_form.selectionBox.setValue(0)
+ else:
+ self.module.view._ui_form.selectionBox.setMaximum(
+ len(self.module.model.measurements) - 1
+ )
+
+ # Clear the measurements list
+ self._ui_form.measurementsList.clear()
+
+ for measurement in self.module.model.measurements:
+ measurement_widget = QWidget()
+ layout = QHBoxLayout()
+ measurement_widget.setLayout(layout)
+
+ delete_button = QPushButton()
+ delete_button.setIcon(Logos.Garbage12x12())
+ delete_button.setFixedWidth(delete_button.iconSize().width())
+ delete_button.clicked.connect(
+ lambda: self.module.controller.delete_measurement(measurement)
+ )
+
+ name_button = QPushButton()
+ name_button.clicked.connect(
+ partial(self.module.controller.change_displayed_measurement, measurement)
+ )
+
+ # Not sure if this is pretty
+ name_button.setProperty("measurement", measurement)
+ name_button.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
+ ) # Set size policy
+
+ layout.addWidget(name_button)
+ layout.addWidget(delete_button)
+ layout.addStretch() # Add stretch after delete button to ensure name button takes up space
+
+ item = QListWidgetItem()
+ item.setSizeHint(measurement_widget.sizeHint())
+
+ self._ui_form.measurementsList.addItem(item)
+ self._ui_form.measurementsList.setItemWidget(item, measurement_widget)
+
+ # Wait for the layout to be updated
+ QApplication.processEvents()
+
+ # Get the contents margins (left, top, right, bottom)
+ content_margins = layout.contentsMargins()
+
+ # Include the margins and spacing in the maxWidth calculation
+ maxWidth = (
+ self._ui_form.measurementsList.width()
+ - delete_button.width()
+ - content_margins.left()
+ - content_margins.right()
+ - layout.spacing()
+ )
+
+ fontMetrics = QFontMetrics(name_button.font())
+ elidedText = fontMetrics.elidedText(
+ measurement.name, Qt.TextElideMode.ElideRight, maxWidth
+ )
+ name_button.setText(elidedText)
+ name_button.setToolTip(measurement.name)
+
class MeasurementDialog(QDialog):
"""This Dialog is shown when the measurement is started and therefore blocks the main window.
diff --git a/src/nqrduck_measurement/widget.py b/src/nqrduck_measurement/widget.py
index bffc892..5655546 100644
--- a/src/nqrduck_measurement/widget.py
+++ b/src/nqrduck_measurement/widget.py
@@ -1,6 +1,6 @@
-# Form implementation generated from reading ui file '../nqrduck-measurement/src/nqrduck_measurement/resources/measurement_widget.ui'
+# Form implementation generated from reading ui file 'measurement_widget.ui'
#
-# Created by: PyQt6 UI code generator 6.5.1
+# Created by: PyQt6 UI code generator 6.7.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
@@ -12,7 +12,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
- Form.resize(1920, 1080)
+ Form.resize(1807, 1080)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -83,6 +83,16 @@ class Ui_Form(object):
self.spsettingsButton = QtWidgets.QPushButton(parent=Form)
self.spsettingsButton.setObjectName("spsettingsButton")
self.settingsLayout.addWidget(self.spsettingsButton)
+ self.label = QtWidgets.QLabel(parent=Form)
+ font = QtGui.QFont()
+ font.setBold(True)
+ font.setWeight(75)
+ self.label.setFont(font)
+ self.label.setObjectName("label")
+ self.settingsLayout.addWidget(self.label)
+ self.measurementsList = QtWidgets.QListWidget(parent=Form)
+ self.measurementsList.setObjectName("measurementsList")
+ self.settingsLayout.addWidget(self.measurementsList)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.settingsLayout.addItem(spacerItem1)
self.dataLayout = QtWidgets.QVBoxLayout()
@@ -105,6 +115,9 @@ class Ui_Form(object):
self.plotter.setSizePolicy(sizePolicy)
self.plotter.setObjectName("plotter")
self.plotterLayout.addWidget(self.plotter)
+ self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_4.setObjectName("horizontalLayout_4")
+ self.plotterLayout.addLayout(self.horizontalLayout_4)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
@@ -119,7 +132,7 @@ class Ui_Form(object):
self.horizontalLayout_3.addItem(spacerItem3)
self.horizontalLayout_3.setStretch(1, 1)
self.plotterLayout.addLayout(self.horizontalLayout_3)
- self.plotterLayout.setStretch(1, 1)
+ self.plotterLayout.setStretch(2, 1)
self.horizontalLayout_2.addLayout(self.plotterLayout)
self.horizontalLayout_2.setStretch(1, 1)
self.horizontalLayout.addLayout(self.horizontalLayout_2)
@@ -142,6 +155,7 @@ class Ui_Form(object):
self.peakButton.setText(_translate("Form", "Peak-Picking"))
self.fittingButton.setText(_translate("Form", "Fitting"))
self.spsettingsButton.setText(_translate("Form", "Settings"))
+ self.label.setText(_translate("Form", "Measurements:"))
self.exportButton.setText(_translate("Form", "Export Measurement"))
self.importButton.setText(_translate("Form", "Import Measurement"))
self.fftButton.setText(_translate("Form", "FFT"))