From fabc86f00f1c6cecfaf1d3a6e80da7dddeffb8cf Mon Sep 17 00:00:00 2001 From: Christoph Schmidt <christoph.,schmidt@tugraz.at> Date: Wed, 3 Jan 2024 20:24:52 +0100 Subject: [PATCH] Updated to Version 1.1.3. Updated some examples and ConfigNode implementations. --- examples/example2/ApplicationConfig.py | 57 +++++++++++ examples/example2/LaserConfig.py | 14 +++ examples/example2/main.py | 96 +++++++++++++++++++ examples/main.py | 6 +- src/confighandler/controller/CSignal.py | 2 +- src/confighandler/controller/ConfigNode.py | 2 +- src/confighandler/controller/Field.py | 15 ++- .../view/fields/FieldViewList.py | 25 ++--- 8 files changed, 200 insertions(+), 17 deletions(-) create mode 100644 examples/example2/ApplicationConfig.py create mode 100644 examples/example2/LaserConfig.py create mode 100644 examples/example2/main.py diff --git a/examples/example2/ApplicationConfig.py b/examples/example2/ApplicationConfig.py new file mode 100644 index 0000000..ea6b63a --- /dev/null +++ b/examples/example2/ApplicationConfig.py @@ -0,0 +1,57 @@ +import logging +import sys +from pathlib import Path + + + +sys.path.append('../src/') + +import confighandler as cfg +from confighandler.controller.SelectableList import SelectableList +from LaserConfig import LaserConfig + + +class ApplicationConfig(cfg.ConfigNode): + + def __init__(self, internal_log=True, internal_log_level= logging.DEBUG) -> None: + super().__init__(internal_log=internal_log, internal_log_level=internal_log_level) + + # self.output_directory: cfg.Field[Path] = cfg.Field(Path("C:\\{wafer_list1}")) + # + # self.wafer_version: cfg.Field[str] = cfg.Field("v1.0", + # friendly_name="wafer_version", + # description="The version of the wafer") + # + # self.wafer_number: cfg.Field[int] = cfg.Field(1, + # friendly_name="wafer_number", + # description="The version of the wafer") + # + # self.check: cfg.Field[bool] = cfg.Field(False, friendly_name="testcheck", + # description="Testcheck") + # + # + # self.wafer_nr: cfg.Field[str] = cfg.Field("12345ABCD_{wafer_number}", + # friendly_name="wafer_nr", + # description="The version of the wafer") + # + # self.wafer_number2: cfg.Field[tuple] = cfg.Field((1, 2), + # friendly_name="wafer_number2", + # description="The version of the wafer") + # + # self.wafer_list: cfg.Field[list] = cfg.Field([1, 2], + # friendly_name="wafer_list", + # description="The version of the wafer") + + self.wafer_list1: cfg.Field[list] = cfg.Field(SelectableList( + [6, 7, 8], + selected_index=0, + description='ms' + ), + friendly_name="wafer_list1", + description="The version of the wafer") + + # self.laser_config: LaserConfig = LaserConfig(internal_log=internal_log, + # internal_log_level=internal_log_level) + + + self.register() diff --git a/examples/example2/LaserConfig.py b/examples/example2/LaserConfig.py new file mode 100644 index 0000000..3d1956b --- /dev/null +++ b/examples/example2/LaserConfig.py @@ -0,0 +1,14 @@ +import confighandler as cfg + + +class LaserConfig(cfg.ConfigNode): + + def __init__(self, internal_log, internal_log_level) -> None: + super().__init__(internal_log=internal_log, internal_log_level=internal_log_level) + self.wavelength_range = cfg.Field(850) + self.velocity = cfg.Field(2.0) + self.acceleration = cfg.Field(1.0) + self.deceleration = cfg.Field(1.0) + self.port = cfg.Field("USB 0") + + self.register() diff --git a/examples/example2/main.py b/examples/example2/main.py new file mode 100644 index 0000000..28e27f6 --- /dev/null +++ b/examples/example2/main.py @@ -0,0 +1,96 @@ +import logging +import sys +import time + +from PySide6 import QtWidgets +from PySide6.QtCore import Signal, QObject +from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget +from rich.logging import RichHandler + +from ApplicationConfig import ApplicationConfig + +class TestClass: + + def _decorator(foo): + def magic(self): + print("start magic") + foo(self) + print("end magic") + + return magic + def __init__(self, config: ApplicationConfig): + self.config = config + self._wafer = 0 + + @property + def wafer(self): + return self._wafer + + @wafer.setter + def wafer(self, value): + self._wafer = value + self.config.wafer_list1.set(value) + print("Wafer changed to", value) + #self.signal.emit(value) + +def test(*args, **kwargs): + print(f"test: {args}, {kwargs}") + +if __name__ == "__main__": + app = QApplication(sys.argv) + + # setup the logging module + + config = ApplicationConfig() + testclass = TestClass(config) + time.sleep(1) + #config.autosave(enable=True, path='./configs_autosave') + config.load('./configs/ApplicationConfig.yaml') + config.autosave(enable=True, path='./') + #print(config.wafer_version) + #config.wafer_version.get() + #config.wafer_number.get() + #print(config.wafer_version) + + window = QMainWindow() + wdg = QWidget() + grd = QtWidgets.QGridLayout() + wdg.setLayout(grd) + grd.addWidget(config.view.widget(), 0, 0) + #grd.addWidget(config.view.widget(), 1, 0) + + tree = QTreeWidget() + + + tree.setColumnCount(3) + tree.setHeaderLabels(["Name", "Type", "asdf"]) + tree.addTopLevelItem(config.view.ui_tree_widget_item(tree)) + grd.addWidget(tree, 2, 0) + + btn_set = QtWidgets.QPushButton("Set Wafer Number to 123") + btn_set.clicked.connect(lambda: config.wafer_nr.set("123")) + grd.addWidget(btn_set, 3, 0) + + btn_save = QtWidgets.QPushButton("Save Config") + 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(test) + + window.setCentralWidget(wdg) + #print(config.load('config.yaml')) + + + window.show() + + sys.exit(app.exec()) + # config.wafer_nr = "1234" + + # config.save("test.yaml") + diff --git a/examples/main.py b/examples/main.py index 2fd56e6..e27cf9c 100644 --- a/examples/main.py +++ b/examples/main.py @@ -3,13 +3,14 @@ import sys import time from PySide6 import QtWidgets +from PySide6.QtCore import Signal from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QTreeWidget from rich.logging import RichHandler from ApplicationConfig import ApplicationConfig class TestClass: - + signal = Signal(int) def __init__(self): self._wafer = 0 @@ -21,6 +22,7 @@ class TestClass: def wafer(self, value): self._wafer = value print("Wafer changed to", value) + self.signal.emit(value) if __name__ == "__main__": @@ -65,6 +67,8 @@ if __name__ == "__main__": 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) diff --git a/src/confighandler/controller/CSignal.py b/src/confighandler/controller/CSignal.py index a1d4494..ee30a58 100644 --- a/src/confighandler/controller/CSignal.py +++ b/src/confighandler/controller/CSignal.py @@ -12,7 +12,7 @@ class CSignal: def emit(self, *args, **kwargs): for connection in self.connections: - connection() + connection(*args, **kwargs) def connect(self, func: callable): self.connections.append(func) diff --git a/src/confighandler/controller/ConfigNode.py b/src/confighandler/controller/ConfigNode.py index 6fb02ba..b96ef09 100644 --- a/src/confighandler/controller/ConfigNode.py +++ b/src/confighandler/controller/ConfigNode.py @@ -191,7 +191,7 @@ class ConfigNode(CObject): # ================================================================================================================== # Functions that happens on a change # ================================================================================================================== - def _on_field_changed(self): + def _on_field_changed(self, *args, **kwargs): # Emit that a field has changed, thus the keywords have changed # print(f"Field changed {self.keywords}") for attr, val in self.fields.items(): diff --git a/src/confighandler/controller/Field.py b/src/confighandler/controller/Field.py index 09a174c..d7f02bc 100644 --- a/src/confighandler/controller/Field.py +++ b/src/confighandler/controller/Field.py @@ -11,6 +11,8 @@ import re from pathlib import Path from typing import Generic, T, TypeVar +from PySide6.QtCore import Signal + import confighandler from confighandler.controller.CObject import CObject from confighandler.controller.CSignal import CSignal @@ -23,12 +25,12 @@ class FieldData(object): self.value = [value, friendly_name, description] - T = TypeVar('T') class Field(Generic[T], CObject): + changed = CSignal() def __init__(self, value: T, friendly_name: str = None, description: str = None, internal_log=True, internal_log_level=logging.INFO): super().__init__() @@ -88,8 +90,13 @@ class Field(Generic[T], CObject): self.props.append((instance, prop)) def _set_all_props(self, value): + # deactivate the set function since this can trigger an infinite loop + bset = self.set + self.set = lambda *args, **kwargs: None for inst, prop in self.props: prop.fset(inst, value) + # Reactive the set function + self.set = bset # ================================================================================================================== # Register the field to a configuration @@ -104,7 +111,6 @@ class Field(Generic[T], CObject): :param csig_field_changed: The signal that is emitted when the keywords are changed """ - self.name = name self.owner = owner formatter = logging.Formatter(f'%(name)s [{self.name}] %(message)s') @@ -186,8 +192,12 @@ class Field(Generic[T], CObject): self.set_keywords() # self.view.value_changed.emit(self.value) # This emits a function that notifies the owner that the field has been set + self.changed.emit(value) self.csig_field_changed.emit() + def connect(self, func): + self.changed.connect(func) + # ================================================================================================================== # Things that should happen when the value is changed # ================================================================================================================== @@ -209,4 +219,3 @@ class Field(Generic[T], CObject): def __repr__(self): return str(f"{self.__class__.__name__}") - diff --git a/src/confighandler/view/fields/FieldViewList.py b/src/confighandler/view/fields/FieldViewList.py index c5a8e95..7678c2e 100644 --- a/src/confighandler/view/fields/FieldViewList.py +++ b/src/confighandler/view/fields/FieldViewList.py @@ -8,7 +8,7 @@ Description: from PySide6 import QtWidgets from PySide6.QtCore import Signal -from PySide6.QtWidgets import QWidget, QLineEdit +from PySide6.QtWidgets import QWidget, QLineEdit, QComboBox from confighandler.view.FieldView import FieldView @@ -17,24 +17,27 @@ class FieldViewList(FieldView): value_changed = Signal(tuple) - def __init__(self, parent_field: 'FieldTuple'): + def __init__(self, parent_field: 'FieldList'): super().__init__(parent_field) - def ui_field(self, view: QLineEdit = None) -> QLineEdit: + def ui_field(self, view: QLineEdit | QComboBox = None) -> QLineEdit: """ """ if view is None: le = QLineEdit(str(self.parent_field.value)) - else: - le: QLineEdit = view le.setToolTip(f"({self.parent_field.name}) {self.parent_field._description}") - self.ui_edit_fields.append(le) - self.ui_edit_fields[-1].textEdited.connect(self._on_text_edited) - # self.ui_edit_fields[-1] : QtWidgets.QLineEdit - self.ui_edit_fields[-1].editingFinished.connect(self._on_edited_finished) - # new - return self.ui_edit_fields[-1] + if isinstance(view, QLineEdit): + le: QLineEdit = view + + self.ui_edit_fields.append(le) + self.ui_edit_fields[-1].textEdited.connect(self._on_text_edited) + # self.ui_edit_fields[-1] : QtWidgets.QLineEdit + self.ui_edit_fields[-1].editingFinished.connect(self._on_edited_finished) + # new + return self.ui_edit_fields[-1] + elif isinstance(view, QComboBox): + cb: QComboBox = view def _on_text_edited(self, value): self.parent_field.set(value) -- GitLab