mirror of
https://github.com/nqrduck/nqrduck-spectrometer.git
synced 2025-01-02 21:58:08 +00:00
Implemented input validation.
This commit is contained in:
parent
837524b69f
commit
e314f51ae4
2 changed files with 83 additions and 35 deletions
|
@ -53,7 +53,7 @@ class BaseSpectrometerView(ModuleView):
|
||||||
setting_label = QLabel(setting.name)
|
setting_label = QLabel(setting.name)
|
||||||
setting_label.setMinimumWidth(200)
|
setting_label.setMinimumWidth(200)
|
||||||
|
|
||||||
edit_widget = setting.get_widget()
|
edit_widget = setting.widget
|
||||||
logger.debug("Setting widget: %s", edit_widget)
|
logger.debug("Setting widget: %s", edit_widget)
|
||||||
|
|
||||||
# Add a icon that can be used as a tooltip
|
# Add a icon that can be used as a tooltip
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot
|
from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot, QRegularExpression
|
||||||
from PyQt6.QtWidgets import QLineEdit, QComboBox, QCheckBox
|
from PyQt6.QtWidgets import QLineEdit, QComboBox, QCheckBox
|
||||||
|
from PyQt6.QtGui import QValidator, QRegularExpressionValidator
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -10,10 +11,21 @@ class Setting(QObject):
|
||||||
E.g. the number of averages or the number of points in a spectrum."""
|
E.g. the number of averages or the number of points in a spectrum."""
|
||||||
settings_changed = pyqtSignal()
|
settings_changed = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, name, description) -> None:
|
def __init__(self, name : str, description : str, default = None) -> None:
|
||||||
|
""" Create a new setting.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): The name of the setting.
|
||||||
|
description (str): A description of the setting.
|
||||||
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.name = name
|
self.name = name
|
||||||
self.description = description
|
self.description = description
|
||||||
|
if default is not None:
|
||||||
|
self.value = default
|
||||||
|
|
||||||
|
# This can be overriden by subclasses
|
||||||
|
self.widget = self.get_widget()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def on_value_changed(self, value):
|
def on_value_changed(self, value):
|
||||||
|
@ -24,7 +36,7 @@ class Setting(QObject):
|
||||||
def get_setting(self):
|
def get_setting(self):
|
||||||
return float(self.value)
|
return float(self.value)
|
||||||
|
|
||||||
def get_widget(self):
|
def get_widget(self):
|
||||||
"""Return a widget for the setting.
|
"""Return a widget for the setting.
|
||||||
The default widget is simply a QLineEdit.
|
The default widget is simply a QLineEdit.
|
||||||
This method can be overwritten by subclasses to return a different widget.
|
This method can be overwritten by subclasses to return a different widget.
|
||||||
|
@ -38,11 +50,34 @@ class Setting(QObject):
|
||||||
widget.editingFinished.connect(lambda x=widget, s=self: s.on_value_changed(x.text()))
|
widget.editingFinished.connect(lambda x=widget, s=self: s.on_value_changed(x.text()))
|
||||||
return widget
|
return widget
|
||||||
|
|
||||||
|
def update_widget_style(self):
|
||||||
|
""" Update the style of the QLineEdit widget to indicate if the value is valid."""
|
||||||
|
logger.debug("Updating widget style")
|
||||||
|
if self.validator.validate(self.widget.text(), 0)[0] == QValidator.State.Acceptable:
|
||||||
|
self.widget.setStyleSheet("QLineEdit { background-color: white; }")
|
||||||
|
elif self.validator.validate(self.widget.text(), 0)[0] == QValidator.State.Intermediate:
|
||||||
|
self.widget.setStyleSheet("QLineEdit { background-color: yellow; }")
|
||||||
|
else:
|
||||||
|
self.widget.setStyleSheet("QLineEdit { background-color: red; }")
|
||||||
|
|
||||||
class FloatSetting(Setting):
|
class FloatSetting(Setting):
|
||||||
""" A setting that is a Float. """
|
""" A setting that is a Float. """
|
||||||
def __init__(self, name : str, default : float, description : str) -> None:
|
DEFAULT_LENGTH = 100
|
||||||
super().__init__(name, description)
|
def __init__(self, name : str, default : float, description : str, validator : QValidator = None) -> None:
|
||||||
self.value = default
|
super().__init__(name, description, default)
|
||||||
|
|
||||||
|
# If a validator is given, set it for the QLineEdit widget
|
||||||
|
if validator:
|
||||||
|
self.validator = validator
|
||||||
|
else:
|
||||||
|
# Create a regex validator that only allows floats
|
||||||
|
regex = "[-+]?[0-9]*\.?[0-9]+"
|
||||||
|
self.validator = QRegularExpressionValidator(QRegularExpression(regex))
|
||||||
|
|
||||||
|
self.widget = self.get_widget()
|
||||||
|
# self.widget.setValidator(self.validator)
|
||||||
|
# Connect the update_widget_style method to the textChanged signal
|
||||||
|
self.widget.textChanged.connect(self.update_widget_style)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
@ -51,16 +86,33 @@ class FloatSetting(Setting):
|
||||||
@value.setter
|
@value.setter
|
||||||
def value(self, value):
|
def value(self, value):
|
||||||
try:
|
try:
|
||||||
self._value = float(value)
|
if self.validator.validate(value, 0)[0] == QValidator.State.Acceptable:
|
||||||
|
self._value = float(value)
|
||||||
|
self.settings_changed.emit()
|
||||||
|
# This should never be reached because the validator should prevent this
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError("Value must be a float")
|
raise ValueError("Value must be a float")
|
||||||
self.settings_changed.emit()
|
# This happens when the validator has not yet been set
|
||||||
|
except AttributeError:
|
||||||
|
self._value = float(value)
|
||||||
|
self.settings_changed.emit()
|
||||||
|
|
||||||
class IntSetting(Setting):
|
class IntSetting(Setting):
|
||||||
""" A setting that is an Integer."""
|
""" A setting that is an Integer."""
|
||||||
def __init__(self, name : str, default : int, description : str) -> None:
|
def __init__(self, name : str, default : int, description : str, validator : QValidator = None) -> None:
|
||||||
super().__init__(name, description)
|
super().__init__(name, description, default)
|
||||||
self.value = default
|
|
||||||
|
# If a validator is given, set it for the QLineEdit widget
|
||||||
|
if validator:
|
||||||
|
self.validator = validator
|
||||||
|
else:
|
||||||
|
# Create a regex validator that only allows integers
|
||||||
|
regex = "[-+]?[0-9]+"
|
||||||
|
self.validator = QRegularExpressionValidator(QRegularExpression(regex))
|
||||||
|
|
||||||
|
self.widget = self.get_widget()
|
||||||
|
# Connect the update_widget_style method to the textChanged signal
|
||||||
|
self.widget.textChanged.connect(self.update_widget_style)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
@ -78,8 +130,10 @@ class BooleanSetting(Setting):
|
||||||
""" A setting that is a Boolean."""
|
""" A setting that is a Boolean."""
|
||||||
|
|
||||||
def __init__(self, name : str, default : bool, description : str) -> None:
|
def __init__(self, name : str, default : bool, description : str) -> None:
|
||||||
super().__init__(name, description)
|
super().__init__(name, description, default)
|
||||||
self.value = default
|
|
||||||
|
# Overrides the default widget
|
||||||
|
self.widget = self.get_widget()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
@ -109,13 +163,15 @@ class BooleanSetting(Setting):
|
||||||
class SelectionSetting(Setting):
|
class SelectionSetting(Setting):
|
||||||
""" A setting that is a selection from a list of options."""
|
""" A setting that is a selection from a list of options."""
|
||||||
def __init__(self, name : str, options : list, default : str, description : str) -> None:
|
def __init__(self, name : str, options : list, default : str, description : str) -> None:
|
||||||
super().__init__(name, description)
|
super().__init__(name, description, default)
|
||||||
# Check if default is in options
|
# Check if default is in options
|
||||||
if default not in options:
|
if default not in options:
|
||||||
raise ValueError("Default value must be one of the options")
|
raise ValueError("Default value must be one of the options")
|
||||||
|
|
||||||
self.options = options
|
self.options = options
|
||||||
self.value = default
|
|
||||||
|
# Overrides the default widget
|
||||||
|
self.widget = self.get_widget()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
@ -123,10 +179,16 @@ class SelectionSetting(Setting):
|
||||||
|
|
||||||
@value.setter
|
@value.setter
|
||||||
def value(self, value):
|
def value(self, value):
|
||||||
if value in self.options:
|
try:
|
||||||
|
if value in self.options:
|
||||||
|
self._value = value
|
||||||
|
else:
|
||||||
|
raise ValueError("Value must be one of the options")
|
||||||
|
# This fixes a bug when creating the widget when the options are not yet set
|
||||||
|
except AttributeError:
|
||||||
self._value = value
|
self._value = value
|
||||||
else:
|
self.options = [value]
|
||||||
raise ValueError("Value must be one of the options")
|
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
|
|
||||||
def get_widget(self):
|
def get_widget(self):
|
||||||
|
@ -164,8 +226,7 @@ class IPSetting(Setting):
|
||||||
class StringSetting(Setting):
|
class StringSetting(Setting):
|
||||||
""" A setting that is a string."""
|
""" A setting that is a string."""
|
||||||
def __init__(self, name : str, default : str, description : str) -> None:
|
def __init__(self, name : str, default : str, description : str) -> None:
|
||||||
super().__init__(name, description)
|
super().__init__(name, description, default)
|
||||||
self.value = default
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
@ -178,17 +239,4 @@ class StringSetting(Setting):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError("Value must be a string")
|
raise ValueError("Value must be a string")
|
||||||
|
|
||||||
self.settings_changed.emit()
|
self.settings_changed.emit()
|
||||||
|
|
||||||
def get_widget(self):
|
|
||||||
"""Return a widget for the setting.
|
|
||||||
The default widget is simply a QLineEdit.
|
|
||||||
This method can be overwritten by subclasses to return a different widget.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
QLineEdit: A QLineEdit widget that can be used to change the setting.
|
|
||||||
"""
|
|
||||||
widget = QLineEdit(str(self.value))
|
|
||||||
widget.setMinimumWidth(100)
|
|
||||||
widget.editingFinished.connect(lambda x=widget, s=self: s.on_value_changed(x.text()))
|
|
||||||
return widget
|
|
Loading…
Reference in a new issue