Skip to content

Commit

Permalink
Merge pull request #17 from nqrduck/3-display-multiple-measurements
Browse files Browse the repository at this point in the history
3 display multiple measurements
  • Loading branch information
jupfi authored May 5, 2024
2 parents 3e516e0 + 278fc5b commit 044b223
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ allow-direct-references = true

[project]
name = "nqrduck-measurement"
version = "0.0.3"
version = "0.0.4"
authors = [
{ name="jupfi", email="[email protected]" },
]
Expand Down
40 changes: 40 additions & 0 deletions src/nqrduck_measurement/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,43 @@ def show_apodization_dialog(self) -> None:

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
16 changes: 15 additions & 1 deletion src/nqrduck_measurement/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -94,6 +95,14 @@ def measurements(self, value: list[Measurement]):
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
Expand All @@ -108,7 +117,12 @@ def displayed_measurement(self):
@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):
Expand Down
25 changes: 22 additions & 3 deletions src/nqrduck_measurement/resources/measurement_widget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1920</width>
<width>1807</width>
<height>1080</height>
</rect>
</property>
Expand All @@ -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">
Expand Down Expand Up @@ -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">
Expand Down Expand Up @@ -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">
Expand All @@ -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>
Expand Down
128 changes: 125 additions & 3 deletions src/nqrduck_measurement/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -50,6 +62,8 @@ def __init__(self, module):
)
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
)
Expand Down Expand Up @@ -105,6 +119,11 @@ def __init__(self, module):
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
Expand Down Expand Up @@ -143,6 +162,18 @@ def update_displayed_measurement(self) -> None:
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
Expand Down Expand Up @@ -173,6 +204,26 @@ def update_displayed_measurement(self) -> None:
# 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()
Expand Down Expand Up @@ -200,7 +251,7 @@ def on_measurement_save_button_clicked(self) -> None:
"""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()
Expand All @@ -212,13 +263,84 @@ def on_measurement_load_button_clicked(self) -> None:
"""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.
Expand Down
Loading

0 comments on commit 044b223

Please sign in to comment.