mirror of
https://github.com/nqrduck/nqrduck-measurement.git
synced 2024-11-09 11:50:01 +00:00
Merge pull request #17 from nqrduck/3-display-multiple-measurements
3 display multiple measurements
This commit is contained in:
commit
044b22393c
7 changed files with 225 additions and 12 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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" },
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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):
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1920</width>
|
||||
<width>1807</width>
|
||||
<height>1080</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1">
|
||||
<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>
|
||||
<widget class="QLabel" name="titleLabel">
|
||||
<property name="font">
|
||||
|
@ -150,6 +150,22 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -184,7 +200,7 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="plotterLayout" stretch="0,1">
|
||||
<layout class="QVBoxLayout" name="plotterLayout" stretch="0,0,1">
|
||||
<item>
|
||||
<widget class="MplWidget" name="plotter" native="true">
|
||||
<property name="sizePolicy">
|
||||
|
@ -195,6 +211,9 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0,0">
|
||||
<item>
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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"))
|
||||
|
|
Loading…
Reference in a new issue