Implemented multiple measurements with deletion option.

This commit is contained in:
jupfi 2024-05-05 15:10:26 +02:00
parent 490ed1356f
commit dca03d288b
5 changed files with 204 additions and 16 deletions

View file

@ -232,12 +232,41 @@ class MeasurementController(ModuleController):
self.module.model.add_measurement(apodized_measurement) self.module.model.add_measurement(apodized_measurement)
@pyqtSlot() @pyqtSlot()
def change_displayed_measurement(self) -> None: def change_displayed_measurement(self, measurement=None) -> None:
"""Change the displayed measurement.""" """Change the displayed measurement."""
logger.debug("Changing displayed measurement.")
if not self.module.model.measurements: if not self.module.model.measurements:
logger.debug("No measurements to display.") logger.debug("No measurements to display.")
return return
index = self.module.view._ui_form.selectionBox.value() if not measurement:
self.module.model.displayed_measurement = self.module.model.measurements[index] 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

View file

@ -50,6 +50,7 @@ class MeasurementModel(ModuleModel):
displayed_measurement_changed = pyqtSignal(Measurement) displayed_measurement_changed = pyqtSignal(Measurement)
measurements_changed = pyqtSignal(list) measurements_changed = pyqtSignal(list)
view_mode_changed = pyqtSignal(str) view_mode_changed = pyqtSignal(str)
measurement_frequency_changed = pyqtSignal(float) measurement_frequency_changed = pyqtSignal(float)
@ -95,10 +96,13 @@ class MeasurementModel(ModuleModel):
"""Add a measurement to the list of measurements.""" """Add a measurement to the list of measurements."""
self.measurements.append(measurement) self.measurements.append(measurement)
# Change the maximum value of the selectionBox. # Change the maximum value of the selectionBox.
self.module.view._ui_form.selectionBox.setMaximum(len(self.measurements)-1) self.measurements_changed.emit(self.measurements)
# Set the correct value of the selectionBox. self.displayed_measurement_changed.emit(measurement)
self.module.view._ui_form.selectionBox.setValue(len(self.measurements)-1)
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) self.measurements_changed.emit(self.measurements)
@property @property
@ -113,7 +117,12 @@ class MeasurementModel(ModuleModel):
@displayed_measurement.setter @displayed_measurement.setter
def displayed_measurement(self, value: Measurement): def displayed_measurement(self, value: Measurement):
self._displayed_measurement = value 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 @property
def measurement_frequency(self): def measurement_frequency(self):

View file

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1920</width> <width>1807</width>
<height>1080</height> <height>1080</height>
</rect> </rect>
</property> </property>
@ -23,7 +23,7 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1"> <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1">
<item> <item>
<layout class="QVBoxLayout" name="settingsLayout" stretch="0,0,0,0,0,0,0,0,0,0,0,0,0"> <layout class="QVBoxLayout" name="settingsLayout" stretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">
<item> <item>
<widget class="QLabel" name="titleLabel"> <widget class="QLabel" name="titleLabel">
<property name="font"> <property name="font">
@ -150,6 +150,22 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Measurements:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="measurementsList"/>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -184,7 +200,7 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="plotterLayout" stretch="0,1"> <layout class="QVBoxLayout" name="plotterLayout" stretch="0,0,1">
<item> <item>
<widget class="MplWidget" name="plotter" native="true"> <widget class="MplWidget" name="plotter" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
@ -195,6 +211,9 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4"/>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0,0"> <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0,0">
<item> <item>

View file

@ -2,7 +2,19 @@
import logging import logging
import numpy as np 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 PyQt6.QtCore import pyqtSlot, Qt
from nqrduck.module.module_view import ModuleView from nqrduck.module.module_view import ModuleView
from nqrduck.assets.icons import Logos 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.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._ui_form.buttonStart.clicked.connect(
self.on_measurement_start_button_clicked self.on_measurement_start_button_clicked
) )
@ -148,6 +162,18 @@ class MeasurementView(ModuleView):
plotter = self._ui_form.plotter plotter = self._ui_form.plotter
plotter.canvas.ax.clear() plotter.canvas.ax.clear()
try: 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: if self.module.model.view_mode == self.module.model.FFT_VIEW:
self.change_to_fft_view() self.change_to_fft_view()
y = self.module.model.displayed_measurement.fdy y = self.module.model.displayed_measurement.fdy
@ -178,6 +204,26 @@ class MeasurementView(ModuleView):
# Add legend # Add legend
self._ui_form.plotter.canvas.ax.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: except AttributeError:
logger.debug("No measurement data to display.") logger.debug("No measurement data to display.")
self._ui_form.plotter.canvas.draw() self._ui_form.plotter.canvas.draw()
@ -224,6 +270,77 @@ class MeasurementView(ModuleView):
if file_name: if file_name:
self.module.controller.load_measurement(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): class MeasurementDialog(QDialog):
"""This Dialog is shown when the measurement is started and therefore blocks the main window. """This Dialog is shown when the measurement is started and therefore blocks the main window.

View file

@ -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 # 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. # 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): class Ui_Form(object):
def setupUi(self, Form): def setupUi(self, Form):
Form.setObjectName("Form") Form.setObjectName("Form")
Form.resize(1920, 1080) Form.resize(1807, 1080)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@ -83,6 +83,16 @@ class Ui_Form(object):
self.spsettingsButton = QtWidgets.QPushButton(parent=Form) self.spsettingsButton = QtWidgets.QPushButton(parent=Form)
self.spsettingsButton.setObjectName("spsettingsButton") self.spsettingsButton.setObjectName("spsettingsButton")
self.settingsLayout.addWidget(self.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) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.settingsLayout.addItem(spacerItem1) self.settingsLayout.addItem(spacerItem1)
self.dataLayout = QtWidgets.QVBoxLayout() self.dataLayout = QtWidgets.QVBoxLayout()
@ -105,6 +115,9 @@ class Ui_Form(object):
self.plotter.setSizePolicy(sizePolicy) self.plotter.setSizePolicy(sizePolicy)
self.plotter.setObjectName("plotter") self.plotter.setObjectName("plotter")
self.plotterLayout.addWidget(self.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 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) 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.addItem(spacerItem3)
self.horizontalLayout_3.setStretch(1, 1) self.horizontalLayout_3.setStretch(1, 1)
self.plotterLayout.addLayout(self.horizontalLayout_3) 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.addLayout(self.plotterLayout)
self.horizontalLayout_2.setStretch(1, 1) self.horizontalLayout_2.setStretch(1, 1)
self.horizontalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout.addLayout(self.horizontalLayout_2)
@ -142,6 +155,7 @@ class Ui_Form(object):
self.peakButton.setText(_translate("Form", "Peak-Picking")) self.peakButton.setText(_translate("Form", "Peak-Picking"))
self.fittingButton.setText(_translate("Form", "Fitting")) self.fittingButton.setText(_translate("Form", "Fitting"))
self.spsettingsButton.setText(_translate("Form", "Settings")) self.spsettingsButton.setText(_translate("Form", "Settings"))
self.label.setText(_translate("Form", "Measurements:"))
self.exportButton.setText(_translate("Form", "Export Measurement")) self.exportButton.setText(_translate("Form", "Export Measurement"))
self.importButton.setText(_translate("Form", "Import Measurement")) self.importButton.setText(_translate("Form", "Import Measurement"))
self.fftButton.setText(_translate("Form", "FFT")) self.fftButton.setText(_translate("Form", "FFT"))