From c4904caf4fb02b2b4d708a00f1d3925463710f97 Mon Sep 17 00:00:00 2001 From: Christoph Schmidt <christoph.,schmidt@tugraz.at> Date: Wed, 20 Dec 2023 10:01:28 +0100 Subject: [PATCH] Updated to Version 1.1.2. Has now the option to connect a property that is automatically set on a field change. --- examples/main.py | 22 +++++++++++++++ src/confighandler/controller/CSignal.py | 1 - src/confighandler/controller/ConfigNode.py | 2 +- src/confighandler/controller/Field.py | 14 +++++++++- .../controller/fields/FieldSelectableList.py | 1 - src/confighandler/view/FieldView.py | 16 +++++++++++ .../view/fields/FieldViewBool.py | 2 +- .../view/fields/FieldViewFloat.py | 2 +- src/confighandler/view/fields/FieldViewInt.py | 2 +- .../view/fields/FieldViewList.py | 2 +- .../view/fields/FieldViewPath.py | 2 +- .../view/fields/FieldViewSelectableList.py | 28 +++---------------- .../view/fields/FieldViewString.py | 2 +- .../view/fields/FieldViewTuple.py | 2 +- 14 files changed, 63 insertions(+), 35 deletions(-) diff --git a/examples/main.py b/examples/main.py index efcca1b..2fd56e6 100644 --- a/examples/main.py +++ b/examples/main.py @@ -8,12 +8,28 @@ from rich.logging import RichHandler from ApplicationConfig import ApplicationConfig +class TestClass: + + def __init__(self): + self._wafer = 0 + + @property + def wafer(self): + return self._wafer + + @wafer.setter + def wafer(self, value): + self._wafer = value + print("Wafer changed to", value) + + if __name__ == "__main__": app = QApplication(sys.argv) # setup the logging module config = ApplicationConfig() + testclass = TestClass() time.sleep(1) #config.autosave(enable=True, path='./configs_autosave') (config.load('./configs/ApplicationConfig.yaml')) @@ -45,6 +61,12 @@ if __name__ == "__main__": btn_save.clicked.connect(lambda: config.save('./configs/ApplicationConfig.yaml')) grd.addWidget(btn_save, 4, 0) + # Add a new combo box + combo = QtWidgets.QComboBox() + grd.addWidget(combo, 5, 0) + config.wafer_list1.view.add_new_view(combo) + config.wafer_list1.connect_property(testclass, TestClass.wafer) + window.setCentralWidget(wdg) #print(config.load('config.yaml')) diff --git a/src/confighandler/controller/CSignal.py b/src/confighandler/controller/CSignal.py index b47c158..a1d4494 100644 --- a/src/confighandler/controller/CSignal.py +++ b/src/confighandler/controller/CSignal.py @@ -11,7 +11,6 @@ class CSignal: self.connections = [] def emit(self, *args, **kwargs): - #print(f"CSignal emit: {args}, {kwargs}") for connection in self.connections: connection() diff --git a/src/confighandler/controller/ConfigNode.py b/src/confighandler/controller/ConfigNode.py index 817f8cc..6fb02ba 100644 --- a/src/confighandler/controller/ConfigNode.py +++ b/src/confighandler/controller/ConfigNode.py @@ -193,7 +193,7 @@ class ConfigNode(CObject): # ================================================================================================================== def _on_field_changed(self): # Emit that a field has changed, thus the keywords have changed - # print(f"Field changed {self.keywords}") + # print(f"Field changed {self.keywords}") for attr, val in self.fields.items(): val: Field val._on_keyword_changed() diff --git a/src/confighandler/controller/Field.py b/src/confighandler/controller/Field.py index b37496a..09a174c 100644 --- a/src/confighandler/controller/Field.py +++ b/src/confighandler/controller/Field.py @@ -23,6 +23,7 @@ class FieldData(object): self.value = [value, friendly_name, description] + T = TypeVar('T') @@ -47,6 +48,9 @@ class Field(Generic[T], CObject): # The view, usd for handling the UI self.view = FieldView(self) + # Connected properties that should bet set if the field changes + self.props = [] + self._internal_logger.debug(f"Field {self.__class__.__name__} created with value {value} of type {type(value)}") def __new__(cls, value, friendly_name: str = None, description: str = None): @@ -80,6 +84,13 @@ class Field(Generic[T], CObject): """Used for serializing instances. Returns the current field as a yaml-line.""" return f"{self.name}: {self._yaml_repr()} # {self.friendly_name}: {self.description}" + def connect_property(self, instance, prop: property): + self.props.append((instance, prop)) + + def _set_all_props(self, value): + for inst, prop in self.props: + prop.fset(inst, value) + # ================================================================================================================== # Register the field to a configuration # ================================================================================================================== @@ -161,6 +172,7 @@ class Field(Generic[T], CObject): By default, the value will be emitted. Overwrite if you need another behavior :return: """ + return self._value def get(self) -> T: @@ -169,6 +181,7 @@ class Field(Generic[T], CObject): def set(self, value: T, *args, force_emit: bool = False, **kwargs): if not self._value_to_emit == value or force_emit: self._internal_logger.info(f"{self.name} = {value} ({type(value)})") + self._set_all_props(value) self._set(value, *args, **kwargs) self.set_keywords() # self.view.value_changed.emit(self.value) @@ -186,7 +199,6 @@ class Field(Generic[T], CObject): def _on_keyword_changed(self): self.set(self._value_to_emit) - # print(f"Field {self.__class__.__name__}._on_keyword_changed called: {self.value}: {str(self.value)}") self.view.value_changed.emit(self._value_to_emit) def _yaml_repr(self): diff --git a/src/confighandler/controller/fields/FieldSelectableList.py b/src/confighandler/controller/fields/FieldSelectableList.py index d74ba0f..6933e6b 100644 --- a/src/confighandler/controller/fields/FieldSelectableList.py +++ b/src/confighandler/controller/fields/FieldSelectableList.py @@ -35,7 +35,6 @@ class FieldSelectableList(ch.Field): return self._value.selected_index def _set(self, value, list = None, description = None): - print(f"FieldSelectableList: {value}, {list}, {description}") if list is not None: self._value = ch.SelectableList(list, selected_index=value, description=description) self.csig_field_changed.emit(self._value_to_emit) diff --git a/src/confighandler/view/FieldView.py b/src/confighandler/view/FieldView.py index cf8227f..6b4645d 100644 --- a/src/confighandler/view/FieldView.py +++ b/src/confighandler/view/FieldView.py @@ -20,6 +20,7 @@ class FieldView(QWidget): def __init__(self, parent_field): super().__init__() + self.parent_field = parent_field self.label = None @@ -33,11 +34,26 @@ class FieldView(QWidget): print(">>> String") def _on_value_changed(self, value): + """ + Updates the UI when the value is changed. + :param value: + :return: + """ + self._on_value_changed_partial(value) + + def _on_value_changed_partial(self, value): + """ + Additional actions when the value is changed. + :param value: + :return: + """ raise NotImplementedError() def add_new_view(self, view: QWidget): self.ui_field(view) + + def ui_field(self, view: QWidget) -> QWidget: """ Returns a QLineEdit for the UI. diff --git a/src/confighandler/view/fields/FieldViewBool.py b/src/confighandler/view/fields/FieldViewBool.py index d0dc2d9..bd99f10 100644 --- a/src/confighandler/view/fields/FieldViewBool.py +++ b/src/confighandler/view/fields/FieldViewBool.py @@ -41,7 +41,7 @@ class FieldViewBool(FieldView): # def _on_keyword_changed(self, keywords): # pass - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): # print(f">>> {self.parent_field.name}: Value changed {value}") for edit in self.ui_edit_fields: edit: QCheckBox # Just for typehinting diff --git a/src/confighandler/view/fields/FieldViewFloat.py b/src/confighandler/view/fields/FieldViewFloat.py index 9ff44c4..1f131ba 100644 --- a/src/confighandler/view/fields/FieldViewFloat.py +++ b/src/confighandler/view/fields/FieldViewFloat.py @@ -40,7 +40,7 @@ class FieldViewFloat(FieldView): def _on_value_edited(self, value): self.parent_field.set(float(value)) - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): # print(f">>> {self.parent_field.name}: Value changed {value}") for edit in self.ui_edit_fields: edit.setValue(float(value)) diff --git a/src/confighandler/view/fields/FieldViewInt.py b/src/confighandler/view/fields/FieldViewInt.py index 345b548..07c1490 100644 --- a/src/confighandler/view/fields/FieldViewInt.py +++ b/src/confighandler/view/fields/FieldViewInt.py @@ -42,7 +42,7 @@ class FieldViewInt(FieldView): # def _on_keyword_changed(self, keywords): # pass - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): #print(f">>> {self.parent_field.name}: Value changed {value}") for edit in self.ui_edit_fields: edit.setValue(int(value)) diff --git a/src/confighandler/view/fields/FieldViewList.py b/src/confighandler/view/fields/FieldViewList.py index 097991c..c5a8e95 100644 --- a/src/confighandler/view/fields/FieldViewList.py +++ b/src/confighandler/view/fields/FieldViewList.py @@ -39,7 +39,7 @@ class FieldViewList(FieldView): def _on_text_edited(self, value): self.parent_field.set(value) - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): for edit in self.ui_edit_fields: edit.setText(str(value)) diff --git a/src/confighandler/view/fields/FieldViewPath.py b/src/confighandler/view/fields/FieldViewPath.py index ab8dd10..2449c67 100644 --- a/src/confighandler/view/fields/FieldViewPath.py +++ b/src/confighandler/view/fields/FieldViewPath.py @@ -70,7 +70,7 @@ class FieldViewPath(FieldView): def _on_text_edited(self, value): self.parent_field.set(value) - def _on_value_changed(self, value: Path): + def _on_value_changed_partial(self, value: Path): # print(value) # Check if path exists for edit, lbl in zip(self.ui_edit_fields, self.ui_edit_fields_lbl): diff --git a/src/confighandler/view/fields/FieldViewSelectableList.py b/src/confighandler/view/fields/FieldViewSelectableList.py index 9f7e3e2..9b6e942 100644 --- a/src/confighandler/view/fields/FieldViewSelectableList.py +++ b/src/confighandler/view/fields/FieldViewSelectableList.py @@ -14,26 +14,6 @@ from PySide6.QtWidgets import QWidget, QLineEdit, QComboBox, QVBoxLayout, QLabel import confighandler as ch -class MyComboBox(QComboBox): - def __init__(self, parent=None): - super(MyComboBox, self).__init__(parent) - self.setContextMenuPolicy() # Qt.CustomContextMenu - - def show_context_menu(self, pos): - index = self.currentIndex() - if index >= 0: - context_menu = QMenu(self) - delete_action = QAction('Delete', self) - delete_action.triggered.connect(self.delete_item) - context_menu.addAction(delete_action) - - action = context_menu.exec_(self.mapToGlobal(pos)) - - def delete_item(self): - index = self.currentIndex() - if index >= 0: - self.removeItem(index) - class FieldViewAddEntry(QWidget): value_changed = Signal(tuple) @@ -129,13 +109,12 @@ class FieldViewSelectableList(ch.FieldView): cb.clear() sel_list = self.parent_field.get_selectable_list() for v in sel_list: - cb.addItem(f"{v[1]} - {v[0]} ", v[0]) + cb.addItem(f"{v[1]}", v[0]) cb.addItem("<Add new ...>", self.add_entry.show) #cb.currentIndexChanged.connect(self._on_index_changed) def show_context_menu(self, pos, field): - print(field) index = field.currentIndex() if index >= 0: context_menu = QMenu(field) @@ -168,8 +147,9 @@ class FieldViewSelectableList(ch.FieldView): self.parent_field.set(len(self.parent_field.get_selectable_list()) - 1) self.parent_field.csig_field_changed.emit() - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): for edit in self.ui_edit_fields: edit: QComboBox - self.parent_field.logger.info(f"{edit}: Setting index to {value}") + # self.parent_field.logger.info(f"{edit}: Setting index to {value}") edit.setCurrentIndex(value) + edit.setToolTip(f"<{edit.currentData()}> ({self.parent_field.name}) {self.parent_field._description}") diff --git a/src/confighandler/view/fields/FieldViewString.py b/src/confighandler/view/fields/FieldViewString.py index 5d1c89b..9f296a0 100644 --- a/src/confighandler/view/fields/FieldViewString.py +++ b/src/confighandler/view/fields/FieldViewString.py @@ -41,7 +41,7 @@ class FieldViewString(FieldView): self.parent_field._internal_logger.debug(f"LineEdit {f} changed to {value}.") self.parent_field.set(value) - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): for edit in self.ui_edit_fields: edit.setText(value) # for tree_item in self.tree_items: diff --git a/src/confighandler/view/fields/FieldViewTuple.py b/src/confighandler/view/fields/FieldViewTuple.py index 32fb814..a8b62ed 100644 --- a/src/confighandler/view/fields/FieldViewTuple.py +++ b/src/confighandler/view/fields/FieldViewTuple.py @@ -39,7 +39,7 @@ class FieldViewTuple(FieldView): def _on_text_edited(self, value): self.parent_field.set(value) - def _on_value_changed(self, value): + def _on_value_changed_partial(self, value): for edit in self.ui_edit_fields: edit.setText(str(value)) -- GitLab