From e97999713ef694c17414ca9126c5d4dc6c6c6923 Mon Sep 17 00:00:00 2001 From: foefl Date: Wed, 20 May 2026 10:09:05 +0200 Subject: [PATCH] extended loading --- prototypes/t_qt_2.py | 445 +++++++++++++++++++++++++------------------ 1 file changed, 260 insertions(+), 185 deletions(-) diff --git a/prototypes/t_qt_2.py b/prototypes/t_qt_2.py index c322474..a3a8183 100644 --- a/prototypes/t_qt_2.py +++ b/prototypes/t_qt_2.py @@ -16,7 +16,16 @@ from typing import Annotated, Any, Protocol, TypeAlias, TypedDict import babel from pydantic import BaseModel, ConfigDict, EmailStr, Field, ValidationError, field_validator -from PySide6.QtCore import QDate, QModelIndex, QStringListModel, Qt, QTimer, Signal +from PySide6.QtCore import ( + QDate, + QEvent, + QModelIndex, + QObject, + QStringListModel, + Qt, + QTimer, + Signal, +) from PySide6.QtGui import QAction, QStandardItem, QStandardItemModel from PySide6.QtWidgets import ( QApplication, @@ -193,8 +202,12 @@ def pprint_registry(widget_registry: WidgetRegistry) -> None: class CustomForm(Protocol): def get_form_data(self) -> dict[str, Any]: ... + def set_form_data(self, data: Any) -> None: ... + def reset_form(self) -> None: ... + def validate_form_data(self) -> list[str]: ... + def _build_ui_recursively( schema: Sequence[FormField], @@ -202,6 +215,7 @@ def _build_ui_recursively( widget_registry: WidgetRegistry, prefix: str = "", ) -> None: + no_scroll_filter = NoScrollFilter(parent_layout) for field in schema: full_key = f"{prefix}.{field.key}" if prefix else field.key widget: QWidget @@ -232,6 +246,7 @@ def _build_ui_recursively( "widget": widget, "form_field": field, } + widget.installEventFilter(no_scroll_filter) if field.tooltip: tooltip_layout = _add_tooltip(widget, field.tooltip) @@ -252,6 +267,7 @@ def _build_ui_recursively( "widget": widget, "form_field": field, } + widget.installEventFilter(no_scroll_filter) if field.tooltip: tooltip_layout = _add_tooltip(widget, field.tooltip) @@ -293,6 +309,7 @@ def _build_ui_recursively( "widget": widget, "form_field": field, } + widget.installEventFilter(no_scroll_filter) if field.tooltip: tooltip_layout = _add_tooltip(widget, field.tooltip) @@ -321,6 +338,7 @@ def _build_ui_recursively( "widget": widget, "form_field": field, } + widget.installEventFilter(no_scroll_filter) if field.tooltip: tooltip_layout = _add_tooltip(widget, field.tooltip) @@ -359,6 +377,7 @@ def _build_ui_recursively( "widget": widget, "form_field": field, } + widget.installEventFilter(no_scroll_filter) if field.tooltip: tooltip_layout = _add_tooltip(widget, field.tooltip) @@ -618,19 +637,11 @@ class Grunderfassung_Unternehmen(BaseModel): Projektrelevanz: Grunderfassung_Projektrelevanz | None = None Kontaktperson: Grunderfassung_Kontaktperson | None = None Stammdaten: Grunderfassung_Stammdaten | None = None + WeitereInfos: Grunderfassung_WeitereInfos | None = None Schulbildung: list[Grunderfassung_Schulbildung] | None = None - - -class Grunderfassung_Schulbildung(BaseModel): - model_config = ConfigDict(str_strip_whitespace=True) - - SB_abschluss: str | None - SB_abschlussgrad: str | None - SB_schule: str | None - SB_ort: str | None - SB_land: str | None - SB_abschlussjahr: str | None - SB_bemerkungsfeld: str | None + HoehereBildung: list[Grunderfassung_HoehereBildung] | None = None + Arbeitserfahrung: list[Grunderfassung_Arbeitserfahrung] | None = None + Sprachkenntnisse: list[Grunderfassung_Sprachen] | None = None class Grunderfassung_Projektrelevanz(BaseModel): @@ -719,6 +730,65 @@ class Grunderfassung_Stammdaten_AnzahlKinder(BaseModel): alter: list[ValidAge | None] | None = None +class Grunderfassung_WeitereInfos(BaseModel): + model_config = ConfigDict(str_strip_whitespace=True) + + WI_deutsch_sprache: str | None + WI_aufenthaltstitel: str | None + WI_gueltigkeit_aufenthaltstitel: datetime.date | None + WI_arbeitsstatus: str | None + WI_meldung_institution: str | None + + +class Grunderfassung_Schulbildung(BaseModel): + model_config = ConfigDict(str_strip_whitespace=True) + + SB_abschluss: str | None + SB_abschlussgrad: str | None + SB_schule: str | None + SB_ort: str | None + SB_land: str | None + SB_abschlussjahr: str | None + SB_bemerkungsfeld: str | None + + +class Grunderfassung_HoehereBildung(BaseModel): + model_config = ConfigDict(str_strip_whitespace=True) + + HB_anerkennung: str | None + HB_abschlussgrad: str | None + HB_abschlussgrad_dokument: str | None + HB_organisation: str | None + HB_beruf: str | None + HB_land: str | None + HB_ort: str | None + HB_abschlussjahr: str | None + HB_bemerkungsfeld: str | None + + +class Grunderfassung_Arbeitserfahrung(BaseModel): + model_config = ConfigDict(str_strip_whitespace=True) + + AE_branche: str | None + AE_bezeichnung: str | None + AE_funktion: str | None + AE_unternehmen: str | None + AE_land: str | None + AE_zeitspanne: str | None + AE_beschaeftigungsart: str | None + AE_bemerkungsfeld: str | None + + +class Grunderfassung_Sprachen(BaseModel): + model_config = ConfigDict(str_strip_whitespace=True) + + SP_sprache: str | None + SP_niveau: str | None + SP_nachweis: str | None + SP_art_nachweis: str | None + SP_datum_nachweis: datetime.date | None + + class CompanyForm_Search(QWidget): company_selected = Signal(int) @@ -1032,21 +1102,21 @@ class WidgetRegistryEntry(TypedDict): WidgetRegistry: TypeAlias = dict[str, WidgetRegistryEntry] -def search_widget_by_key( +def search_widgets_by_key( widget_registry: WidgetRegistry, key_part: str, -) -> QWidget | None: +) -> list[WidgetRegistryEntry]: """ needed for custom logic of auto-built forms, search for specific keys and obtain the widget to assign special logic or callbacks to them """ - hit: QWidget | None = None + hits: list[WidgetRegistryEntry] = [] for key, entry in widget_registry.items(): if key_part in key: - hit = entry["widget"] + hits.append(entry) - return hit + return hits FORM_FIELDS_CONTACT_PERSON = [ @@ -1258,14 +1328,6 @@ FORM_FIELDS_MASTER_DATA = [ required=False, tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", ), - # FormField( - # "Anzahl Kinder", - # FormFieldType.DYNAMIC_DROPDOWN, - # key="Stammdaten_anzahl_kinder", - # required=False, - # options=[(str(x), None) for x in range(11)], - # tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", - # ), FormField( "Anzahl Kinder", FormFieldType.DYNAMIC_DROPDOWN, @@ -1293,6 +1355,7 @@ FORM_FIELDS_ADDITIONAL_DATA = [ "Deutsch als Kommunikationssprache", FormFieldType.DROPDOWN, required=False, + key="WI_deutsch_sprache", options=[ ("nein", None), ("ja, als Muttersprache", None), @@ -1303,6 +1366,7 @@ FORM_FIELDS_ADDITIONAL_DATA = [ "Aufenthaltstitel", FormFieldType.DROPDOWN, required=False, + key="WI_aufenthaltstitel", options=[ ("anerkannter Flüchtling §§ 22 - 26 AufenthG", None), ("Aufenthaltsgestattung §55 AufenthG", None), @@ -1325,11 +1389,13 @@ FORM_FIELDS_ADDITIONAL_DATA = [ "Gültigkeit Aufenthaltsstatus", FormFieldType.DATE, required=False, + key="WI_gueltigkeit_aufenthaltstitel", ), FormField( "Arbeitsstatus aktuell", FormFieldType.DROPDOWN, required=False, + key="WI_arbeitsstatus", options=[ ("Arbeitslos", None), ("Ausbildung/Qualifizierung Inland", None), @@ -1345,6 +1411,7 @@ FORM_FIELDS_ADDITIONAL_DATA = [ "Gemeldet bei Institutionen ", FormFieldType.DROPDOWN, required=False, + key="WI_meldung_institution", options=[ ("bei keiner", None), ("Jobcenter mit Leistungsbezug", None), @@ -1399,11 +1466,13 @@ FORM_FIELDS_HIGHER_EDUCATION = [ "Anerkennung", FormFieldType.TEXT, required=False, + key="HB_anerkennung", ), FormField( "Abschlussgrad", FormFieldType.TEXT, required=False, + key="HB_abschlussgrad", tooltip=( "bitte den Titel eingeben z.B. Doktor, Diplom oder " "Betriebswirt (Fachschulabschluss)" @@ -1413,16 +1482,19 @@ FORM_FIELDS_HIGHER_EDUCATION = [ "Abschlussgrad laut Dokument", FormFieldType.TEXT, required=False, + key="HB_abschlussgrad_dokument", ), FormField( "Hochschule / Ausbildungsbetrieb / Berufsschule", FormFieldType.TEXT, required=False, + key="HB_organisation", ), FormField( "Beruf / Fachrichtung", FormFieldType.TEXT, required=False, + key="HB_beruf", tooltip=( "bitte spezifizieren z.B. Allgemeinmedizin, Ingenieur Maschinenbau, " "technischer Betriebswirt Datenverarbeitung" @@ -1431,7 +1503,7 @@ FORM_FIELDS_HIGHER_EDUCATION = [ FormField( "Land", FormFieldType.EXTENDED_DROPDOWN, - key="country", + key="HB_land", required=False, placeholder="Suche...", options=COUNTRY_LIST.for_dropdown, @@ -1440,16 +1512,19 @@ FORM_FIELDS_HIGHER_EDUCATION = [ "Ort", FormFieldType.TEXT, required=False, + key="HB_ort", ), FormField( "Abschlussjahr", FormFieldType.TEXT, required=False, + key="HB_abschlussjahr", ), FormField( "Bemerkungsfeld", FormFieldType.TEXT, required=False, + key="HB_bemerkungsfeld", tooltip="z.B. Promotionen oder den Studiengang angeben", ), ] @@ -1459,17 +1534,20 @@ FORM_FIELDS_WORK_EXPERIENCE = [ "Branche", FormFieldType.DROPDOWN, required=False, + key="AE_branche", options=[("DROPDOWN-LISTE AN ANDERER STELLE DEFINIERT", None)], ), FormField( "Berufsbezeichnung/Tätigkeit", FormFieldType.TEXT, required=False, + key="AE_bezeichnung", ), FormField( "Funktion", FormFieldType.DROPDOWN, required=False, + key="AE_funktion", options=[ ("Auszubildender", None), ("Fachkraft", None), @@ -1487,11 +1565,12 @@ FORM_FIELDS_WORK_EXPERIENCE = [ "Unternehmen", FormFieldType.TEXT, required=False, + key="AE_unternehmen", ), FormField( "Land", FormFieldType.EXTENDED_DROPDOWN, - key="country", + key="AE_land", required=False, placeholder="Suche...", options=COUNTRY_LIST.for_dropdown, @@ -1500,11 +1579,13 @@ FORM_FIELDS_WORK_EXPERIENCE = [ "Zeitspanne (von ... bis ...)", FormFieldType.TEXT, required=False, + key="AE_zeitspanne", ), FormField( "Beschäftsigungsart", FormFieldType.DROPDOWN, required=False, + key="AE_beschaeftigungsart", options=[ ("Vollzeit", None), ("Teilzeit", None), @@ -1516,6 +1597,7 @@ FORM_FIELDS_WORK_EXPERIENCE = [ "Bemerkungsfeld", FormFieldType.TEXT, required=False, + key="AE_bemerkungsfeld", ), ] @@ -1524,11 +1606,13 @@ FORM_FIELDS_LANGUAGES = [ "Sprache", FormFieldType.TEXT, required=False, + key="SP_sprache", ), FormField( "Niveau", FormFieldType.DROPDOWN, required=False, + key="SP_niveau", options=[ ("A1", None), ("A2", None), @@ -1542,6 +1626,7 @@ FORM_FIELDS_LANGUAGES = [ "Nachweis", FormFieldType.DROPDOWN, required=False, + key="SP_nachweis", options=[ ("vorhanden", None), ("nicht vorhanden", None), @@ -1551,93 +1636,74 @@ FORM_FIELDS_LANGUAGES = [ "Art des Nachweises (NUR WENN VORHANDEN)", FormFieldType.TEXT, required=False, + key="SP_art_nachweis", ), FormField( "Datum des Nachweises (NUR WENN VORHANDEN)", FormFieldType.DATE, required=False, + key="SP_datum_nachweis", ), ] FORM_FIELDS = [ - # FormField( - # "Status && Projektrelevanz", - # FormFieldType.GROUP, - # key="Projektrelevanz", - # children=[ - # FormField( - # "Projektrelevanz", - # FormFieldType.DROPDOWN, - # key="Projektrelevanz_relevanz", - # required=True, - # options=[("ja", None), ("nein", None)], - # ), - # ], - # ), - # FormField( - # "Daten Kontaktperson", - # FormFieldType.GROUP, - # key="Kontaktperson", - # children=FORM_FIELDS_CONTACT_PERSON, - # ), + FormField( + "Status && Projektrelevanz", + FormFieldType.GROUP, + key="Projektrelevanz", + children=[ + FormField( + "Projektrelevanz", + FormFieldType.DROPDOWN, + key="Projektrelevanz_relevanz", + required=True, + options=[("ja", None), ("nein", None)], + ), + ], + ), + FormField( + "Daten Kontaktperson", + FormFieldType.GROUP, + key="Kontaktperson", + children=FORM_FIELDS_CONTACT_PERSON, + ), FormField( "Stammdaten", FormFieldType.GROUP, key="Stammdaten", children=FORM_FIELDS_MASTER_DATA, ), + FormField( + "Weitere Informationen", + FormFieldType.GROUP, + key="WeitereInfos", + children=FORM_FIELDS_ADDITIONAL_DATA, + ), FormField( "Schulbildung", FormFieldType.DYNAMIC_LIST, children=FORM_FIELDS_SCHOOL, key="Schulbildung", ), - # FormField( - # "Test Länderauswahl", - # FormFieldType.GROUP, - # key="countries", - # children=[ - # FormField( - # "Länderauswahl", - # FormFieldType.EXTENDED_DROPDOWN, - # key="country", - # required=True, - # placeholder="Suche...", - # options=COUNTRY_LIST.for_dropdown, - # ), - # ], - # ), - # FormField( - # "Anzahl Kinder (dynamischer Dropdown)", - # FormFieldType.DYNAMIC_DROPDOWN, - # required=False, - # options=[(str(x), None) for x in range(11)], - # tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", - # key="DynamicDropdown", - # children=[ - # FormField( - # "Anzahl Kinder", - # FormFieldType.DROPDOWN, - # required=False, - # options=[(str(x), None) for x in range(11)], - # tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", - # key="MainDropdown", - # children=[ - # FormField("Alter Kind", FormFieldType.TEXT), - # ], - # ), - # ], - # ), - # FormFieldGroup("Daten Kontaktperson", FORM_FIELDS_CONTACT_PERSON), - # FormFieldGroup("Stammdaten (ERGÄNZUNG KINDERALTER DYNAMISCH)", FORM_FIELDS_MASTER_DATA), - # FormFieldGroup("weitere Informationen", FORM_FIELDS_ADDITIONAL_DATA), - # FormFieldGroup("Schule (MIT PLUS-ERWEITERUNG)", FORM_FIELDS_SCHOOL), - # FormFieldGroup("Studium/Ausbildung (MIT PLUS-ERWEITERUNG)", FORM_FIELDS_HIGHER_EDUCATION), - # FormFieldGroup("Arbeitserfahrung (MIT PLUS-ERWEITERUNG)", FORM_FIELDS_WORK_EXPERIENCE), - # FormFieldGroup("Sprachkenntnisse (MIT PLUS-ERWEITERUNG)", FORM_FIELDS_LANGUAGES), - # FormFieldGroup("Dynamische Liste", FORM_DYN_LIST), - # FormFieldGroup("Test-2", FORM_FIELD_DEF2), + FormField( + "Studium/Ausbildung", + FormFieldType.DYNAMIC_LIST, + children=FORM_FIELDS_HIGHER_EDUCATION, + key="HoehereBildung", + ), + FormField( + "Arbeitserfahrung", + FormFieldType.DYNAMIC_LIST, + children=FORM_FIELDS_WORK_EXPERIENCE, + key="Arbeitserfahrung", + ), + FormField( + "Sprachkenntnisse", + FormFieldType.DYNAMIC_LIST, + children=FORM_FIELDS_LANGUAGES, + key="Sprachkenntnisse", + ), ] @@ -1678,6 +1744,8 @@ class AutoForm(QWidget): image: none; } """) + # --- special funtionality --- + self.no_scroll_filter = NoScrollFilter(self) # --- LAYOUT --- self.main_layout = QVBoxLayout(self) @@ -1740,11 +1808,11 @@ class AutoForm(QWidget): self.save_btn.setText(self.save_btn_txt_enabled) def on_load_clicked(self) -> None: + # TODO change logic to database backend print(">>>> LOAD CLICKED") loaded_data = load_pydantic_model_dict() # print("Loaded dictionary:") # pprint(loaded) - # print(">>>> Widget registry:") # pprint_registry(self.widget_registry) @@ -1755,48 +1823,11 @@ class AutoForm(QWidget): key_path = key.split(".") value = _get_nested(loaded_data, key_path) - # print(f"Key: {key}") - # print(f"Value: {value}") - - # Wenn kein Wert da ist (z.B. weil er optional ist), überspringen wir das Feld - if value is None: - continue - elif value is True: - value = "ja" - elif value is False: - value = "nein" - - # 2. Das Widget entsprechend seinem Typ füllen - if isinstance(widget, QLineEdit): - widget.setText(str(value)) # str() zur Sicherheit, falls es ein int ist - - elif isinstance(widget, QComboBox): - # MEGA WICHTIG: Wir suchen nicht den Text, sondern die unsichtbaren Daten! - # (z.B. suchen wir nach dem ISO-Code 'DE' oder der ID 1042) - index = widget.findData(value) - if index >= 0: - widget.setCurrentIndex(index) - - elif isinstance(widget, (DynamicListWidget, DynamicDropdownWidget)): - print("\n-----------------\n\nCustom widget, skip...") - print(f"Key: {key}") - print("Widget type: ", type(widget).__name__) - print("current value or data format: ") - pprint(value) - - if hasattr(widget, "set_form_data"): - widget.set_form_data(value) # type: ignore - - continue - - # elif hasattr(widget, "set_data"): - # # Wenn es eins unserer Custom-Widgets ist (Dropdown-Liste, Dynamische Liste) - # # übergeben wir die Liste einfach an das Widget selbst! - # widget.set_data(wert) + set_widget_value(widget, value) def on_save_clicked(self) -> None: self._disable_save() - errors = validate_form_data(self.widget_registry) + errors = self.validate_form_data() if errors: # errors: abort saving and show pop up window @@ -1813,54 +1844,47 @@ class AutoForm(QWidget): print("Erfolg! Alle Daten sind valide.") print("Get form data call...") form_data = self.get_form_data() - # post_proc_1 = form_data["Stammdaten"]["Stammdaten_anzahl_kinder"] - - # Stammdaten_anzahl_kinder = post_proc_1[0]["Stammdaten_anzahl_kinder-[0]"][ - # "'Stammdaten_anzahl_kinder'" - # ] - # Stammdaten_alter_kinder: list[str] = [] - # if len(post_proc_1) > 1: - # for i in range(1, len(post_proc_1)): - # content = post_proc_1[i] - print("------------>>>>>>>>> Get form data") pprint(form_data) - print("------------>>>>>>>>> Call Pydantic") + print("\n------------>>>>>>>>> Call Pydantic") try: validated_data = Grunderfassung_Unternehmen(**form_data) - # validated_data = Grunderfassung_Stammdaten(**form_data["Stammdaten"]) pprint(validated_data.model_dump()) except ValidationError as e: - # 4. Fehler abfangen und in der GUI anzeigen! + # catch errors and show them in GUI fehler_texte = [] - # Pydantic liefert eine detaillierte Fehlerliste + # Pydantic detailed error list for error in e.errors(): print(error) - # error['loc'][0] enthält den Namen des Feldes (z.B. 'email') + # error['loc'][0] = name of field fehlerhaftes_feld = str(error["loc"][0]) grund = error["msg"] fehler_texte.append(f"- {fehlerhaftes_feld}: {grund}") - # Wir machen das betroffene Widget in PySide rot! + # formatting red # if fehlerhaftes_feld in self.widgets: # self.widgets[fehlerhaftes_feld].setStyleSheet( # "border: 1px solid red; background: #fef2f2;" # ) - # Dem Nutzer gesammelt mitteilen, was schiefgelaufen ist + # tell user what went wrong QMessageBox.warning(self, "Eingabefehler", "\n".join(fehler_texte)) else: - # !! keep this code must be called again + # !! this code is only called if the 'try' block was successful self.reset_form() save_pydantic_model_dict(validated_data) finally: + # always re-enable save, even if error occurred self._enable_save() # ------------------------------------------------------------ + def validate_form_data(self) -> list[str]: + return validate_form_data(self.widget_registry) + def reset_form(self) -> None: reset_form(self.widget_registry) @@ -1870,6 +1894,54 @@ class AutoForm(QWidget): return raw_data +def set_widget_value( + widget: QWidget, + value: Any, +) -> None: + if value is None: + return + elif value is True: + value = "ja" + elif value is False: + value = "nein" + + if isinstance(widget, QLineEdit): + widget.setText(str(value)) + + elif isinstance(widget, QPlainTextEdit): + widget.setPlainText(str(value)) + + elif isinstance(widget, QDateEdit): + assert isinstance(value, datetime.date) + set_date = QDate(value.year, value.month, value.day) + if not set_date.isValid(): + raise ValueError(f"Could not parse date field value >{value}<") + widget.setDate(set_date) + + elif isinstance(widget, QComboBox): + index = widget.findData(value) + if index >= 0: + widget.setCurrentIndex(index) + + elif isinstance(widget, DynamicListWidget): + # print("\n-----------------\n\nCustom widget...") + # print(f"Key: {key}") + # print("Widget type: ", type(widget).__name__) + # print("current value or data format: ") + # pprint(value) + assert isinstance(value, list) + widget.set_form_data(value) + + elif isinstance(widget, DynamicDropdownWidget): + # print("\n-----------------\n\nCustom widget, skip...") + # print(f"Key: {key}") + # print("Widget type: ", type(widget).__name__) + # print("current value or data format: ") + # pprint(value) + assert isinstance(value, dict) + widget.set_form_data(value) + + @dc.dataclass(slots=True) class SubForm: entry_box: QWidget @@ -1996,15 +2068,14 @@ class DynamicListWidget(QWidget): # pprint_registry(self.widget_registry) def reset_form(self) -> None: - reset_form(self.widget_registry) + while self.sub_forms: + self.remove_entry(self.sub_forms[0]) + + self.add_entry() def validate_form_data(self) -> list[str]: return validate_form_data(self.widget_registry) - def load_form_data(self) -> None: - # TODO add way to load data when initialised (probably with click) - ... - def get_form_data(self): raw_data = get_form_data(self.widget_registry) @@ -2018,19 +2089,23 @@ class DynamicListWidget(QWidget): while self.sub_forms: self.remove_entry(self.sub_forms[0]) - # empyt default row + # empty default row if not data: self.add_entry() return - # TODO rework - for entry in data: + for sub_data in data: self.add_entry() + current_sub_form = self.sub_forms[-1] + registry_entries = search_widgets_by_key( + self.widget_registry, f"-[{current_sub_form.index}]" + ) + for reg_entry in registry_entries: + widget = reg_entry["widget"] + field_def = reg_entry["form_field"] - # get all relevant widgets and fill in the values - # current_sub_form = self.sub_forms[-1] - - # fill in values + value = sub_data[field_def.key] + set_widget_value(widget, value) class DynamicDropdownWidget(QWidget): @@ -2163,10 +2238,6 @@ class DynamicDropdownWidget(QWidget): def validate_form_data(self) -> list[str]: return validate_form_data(self.widget_registry) - def load_form_data(self) -> None: - # TODO add way to load data when initialised (probably with click) - ... - def get_form_data(self): raw_data = get_form_data(self.widget_registry) # each sub form has its own numbered key: We need to get rid of these @@ -2202,32 +2273,21 @@ class DynamicDropdownWidget(QWidget): while self.sub_forms: self._remove_row() - # empty default line - # !! only dynamic list widget - # if not daten_liste: - # self._add_row() - # return - # fill in value of combobox field entries = tuple(self.widget_registry.values()) assert len(entries) == 1 widget = entries[0]["widget"] assert isinstance(widget, QComboBox) - value = data["anzahl"] - index = widget.findData(value) - if index >= 0: - widget.setCurrentIndex(index) + value = data[self.combobox_field.key] + set_widget_value(widget, value) - data_list: list[int | None] | None = data["alter"] + data_list: list[int | None] | None = data[self.assigned_form_field.key] if not data_list: return # now there are as many new sub forms as the saved value for the dropdown # assert this assert len(data_list) == len(self.sub_forms) - print(">>>>>>> New Registry of dynamic dropdown:") - pprint_registry(self.widget_registry) - sub_form_index: int = 0 for key, entry in self.widget_registry.items(): if "-[0]" in key: @@ -2235,13 +2295,28 @@ class DynamicDropdownWidget(QWidget): continue widget = entry["widget"] value = data_list[sub_form_index] - if value is None: - value = "" - if isinstance(widget, QLineEdit): - widget.setText(str(value)) + set_widget_value(widget, value) sub_form_index += 1 +class NoScrollFilter(QObject): + """disables scrolling in fields which are not in focus""" + + def eventFilter( + self, + obj: QObject, + event: QEvent, + ) -> bool: + if event.type() == QEvent.Type.Wheel: + # ignored Qt gives event to parent (ScrollArea) + event.ignore() + # event was handled + return True + + # propagate other events + return super().eventFilter(obj, event) + + class ClickableCell(QFrame): """cell in the table on the startup screen"""