Objekte verschiedener Kindklassen vergleichen - Druckversion +- LabVIEWForum.de (https://www.labviewforum.de) +-- Forum: LabVIEW (/Forum-LabVIEW) +--- Forum: LabVIEW Allgemein (/Forum-LabVIEW-Allgemein) +---- Forum: LVOOP (/Forum-LVOOP) +---- Thema: Objekte verschiedener Kindklassen vergleichen (/Thread-Objekte-verschiedener-Kindklassen-vergleichen) Seiten: 1 2 |
Objekte verschiedener Kindklassen vergleichen - seuk - 27.06.2019 09:50 Hallo Zusammen, ich fange gerade erst damit an, mir ein wenig Objektorientierung in LV anzuschauen und bin bereits auf ein Problem gestoßen: Der Versuch dient dazu ein Modul "Settings Editor" zu erstellen, welches alle Einstellungsoptionen für verschiedene Module enthält. Ich möchte zwar nicht zu weit ausholen, doch ein bisschen Kontext schadet meist auch nicht. Ich habe eine Elternklasse: AbstractSetting Und zwei Kindklassen: ConcreteSettingA, ConcreteSettingB Nun sollen meine Module jeweils ein Array von AbstractSetting haben, der "Settings Editor" hält für jedes Modul entsprechend das gleiche Array. Tatsächlich werden in den Arrays natürlich verschiedene Objekte der Kindklassen gespeichert. Beim Start des Programm, läd der "Settings Editor" eine XML Datei, füllt seine Arrays und verteilt die Settings an die Module. Nun verstellt der Anwender diverse Einstellungen in der GUI des "Settings Editor" und drückt auf OK. In dem Moment habe ich zwei Arrays von AbstractSettings, eines enthält die aktuellen Daten, ein anderes die neuen. Nun sollen nur die tatsächlichen Änderungen an den Kindklassen an die Module propagiert werden. Wie finde ich die heraus? Mein Ansatz: Ich durchlaufe die Arrays in einer Schleife if AbstractSettingNeu[0].isEqual(AbstractSettingAlt[0]) == false AbstractSettingNeu[0].broadcastSettingsChange() Ich kann eine Methode broadcastSettingsChange() in der Elternklasse erstellen, und in der Kindklasse überschreiben (Stichwort Dynamic Dispatch). Ich kann aber keine Methode isEqual in der Elternklasse erstellen, welche zwei Inputs von AbstractSetting mit Dynamic Dispatch zulässt. Ist ja auch klar, woher soll LV wissen, welche Kindklasse die Methode überschreibt, wenn es mit zwei verschiedenen Kindklassen aufgerufen werden würde? Ich stehe leider gerade etwas auf dem Schlauch und würde mich über Hinweise freuen. RE: Objekte verschiedener Kindklassen vergleichen - GerdW - 27.06.2019 10:32 Hallo seuk, Zitat:Nun sollen nur die tatsächlichen Änderungen an den Kindklassen an die Module propagiert werden. Wie finde ich die heraus?Kannst du nicht noch ein Flag zu den Klassen-Daten hinzufügen, welches dir anzeigt, ob der Editor etwas an den Settings geändert hat? Dann hast du nur noch: Code: IF ClassData.IsChanged THEN Zitat:In dem Moment habe ich zwei Arrays von AbstractSettings, eines enthält die aktuellen Daten, ein anderes die neuen.Das verstehe ich nicht: es gehen Daten in den Editor rein und es kommen (evtl. angepasste) Daten heraus (DATFLOW). Wieso hast du jetzt zweifach Daten? RE: Objekte verschiedener Kindklassen vergleichen - IchSelbst - 27.06.2019 10:42 (27.06.2019 10:32 )GerdW schrieb: es gehen Daten in den Editor rein und es kommen (evtl. angepasste) Daten heraus (DATFLOW). Wieso hast du jetzt zweifach Daten?Da kann ich noch helfen: Wie im Event Value(Changed): "Neuer Wert", "Alter Wert". RE: Objekte verschiedener Kindklassen vergleichen - seuk - 27.06.2019 11:09 Hallo GerdW, (27.06.2019 10:32 )GerdW schrieb:Zitat:In dem Moment habe ich zwei Arrays von AbstractSettings, eines enthält die aktuellen Daten, ein anderes die neuen.Das verstehe ich nicht: es gehen Daten in den Editor rein und es kommen (evtl. angepasste) Daten heraus (DATFLOW). Wieso hast du jetzt zweifach Daten? Änderungen sollen erst propagiert werden, wenn der Anwender auf OK klickt - drückt er auf Abbrechen, müssen die bisherigen Einstellungen beibehalten werden. Dazu mein Ansatz - die Änderungen an den Bedienelementen gehen die neuen Werte sofort per Event Struktur in eine Kopie des Arrays - bei Knopfdruck OK: Array ALT mit Array NEU vergleichen --> nur Änderungen an einzelnen Bedienelementen kommunizieren - bei Knopfdruck Abbrechen: Array Alt auslesen und Bedienelemente auf dessen Werte setzen. Ich bin aber offen für schlauere Lösungsmöglichkeiten. Die Idee mit dem Flag werde ich mal durchdenken. Ich glaube ich habe mein Klassendesign noch nicht schlau gelöst! Konkrete Settings Klassen wären z.B. TemperatureRange und TemperatureUnit An der oben genannten Stelle des Settings Editor wäre es schön all diese Settings Klassen in einem Array durchlaufen zu können, um sowas wie if isEqual() then sendData() machen zu können. Damit hier keine Änderungen bei Erweiterungen nötig werden würden. Andererseits muss ich ja auch irgendwo die konkreten Werte in die Settingsklassen bekommen und wieder auslesen können. Die Getter und Setter für die konkreten Settingsklassen wären unproblematisch (z.B. TemperatureRange.getMin() ). Aber woher weiß ich denn, an welcher Stelle des Arrays welche Settingsklasse ist? Dies würde dafür sprechen alle Settingsklassen in einen Cluster zu packen. Hmm, muss ich hier einen Tod sterben, oder bekomme ich irgendwie die beiden Vorteile von Cluster und Arrays vereint? Ich wollte hier eigentlich nicht so stark vom Thema abdriften. Hab mich nun schon mit Variant Lookup Tables, Current Values Tables und den neuen MAP und SET Datenstrukturen von LV2019 eingelesen. Ich dachte mit Klassen könnte ich dem Problem besser begegnen, aber vielleicht liegt mein Problem auch ganz woanders...? Ich möchte Typsicherheit schon bei Edittime erreichen, damit sind Variants raus. Zudem möchte ich bei Erweiterungen eine zentrale Definition, wie eben ne TypeDef oder Klasse, anpassen und dann so wenig wie möglich ändern, bzw. hinzufügen müssen. RE: Objekte verschiedener Kindklassen vergleichen - IchSelbst - 27.06.2019 11:45 Bevor ich hier weiter nachdenke, müssen wir erst mal mein Verständnis abgleichen. (27.06.2019 09:50 )seuk schrieb: Der Versuch dient dazu ein Modul "Settings Editor" zu erstellen, welches alle Einstellungsoptionen für verschiedene Module enthält.Du möchtest also schreiben ein Programm-Modul, das folgendes macht: 1. Zuerst bekommt das Modul von irgendwo her ("Herkunfsmodul") eine bestimmte Anzahl von Datenwerten, womöglich zusammengefasst als Cluster/Struct. Diese Daten sind dort, wo sie herkommen, z.B. Einstellparameter ("Settings") 2. Diese Daten sollen angezeigt werden und vom Anwender geändert werden können: "SettingsEditor". 3. Sobald der Anwender sein OK für die geänderten Datenwerte gibt, sollen diese oder auch der ganze neue Datensatz zurück an das Herkunftsmodul. 4. Der Selbstzweck deines Programmmoduls ist also die Anzeige und Eingabe von Daten. Sehe ich das richtig? So grob wie das hier steht, ist das ja ohne Typdefinition der Daten. Das geht aber nicht. Fazit: Es werden nicht die Datenwerte übergeben, sondern tatsächlich Datenwerte samt deren Typdefinition. Sowas ist möglich ("Laufzeit-Typ-Information"? RTTI?). Ein Variant z.B. kann das. Und eine Referenz auf Cluster auch. XML-Files auch. Text-basierte Sprachen auch. Das Problem ist, dass das Modul typ-abhängige Eingabeelemente braucht. Wie hast du das Problem der typ-abhängigen Eingabe gelöst? Siehst du hier überhaupt ein Problem? Das Schöne an so Sachen wie .IsEqual oder .ToString, dass die ja in der objektorientierten Sprache systemimmanent im Datenobjekt sind. D.h. der Programmierer muss sich hier um nichts kümmern, muss sich also nicht um die Typverträglichkeit kümmern. In LabVIEW müsstest du eine Funktionalität generieren, die in objekt-orientierten System bereits integriert ist. Siehst du das auch so? Man kann in LV VIs so gestalten, dass sie abhängig von Eingangsparameter unterschiedlichen Code ausführen. Wie das genau geht, weiß ich nicht. Ich hatte bisher noch keine Veranlassung sowas zu verwenden. RE: Objekte verschiedener Kindklassen vergleichen - th13 - 27.06.2019 11:48 (27.06.2019 11:09 )seuk schrieb: oder bekomme ich irgendwie die beiden Vorteile von Cluster und Arrays vereint?Wenn du eine Referenz auf den Cluster hast, kannst du Mittels der Controls-Eigenschaft alle Elemente des Clusters in einer Schleife durchgehen. (27.06.2019 11:45 )IchSelbst schrieb: Man kann in LV VIs so gestalten, dass sie abhängig von Eingangsparameter unterschiedlichen Code ausführen. Wie das genau geht, weiß ich nicht. Ich hatte bisher noch keine Veranlassung sowas zu verwenden.Das sind polymorphe VIs, falls seuk in der Richtung weiter schauen will. Ich finde die LabVIEW-Umsetzung allerdings nicht sehr elegant. Im Prinzip legt man für jeden Typ des Eingangsparameters ein eigenes VI an und definiert ein Top-VI (das ist dann das mit der Polymorphy), das je nach Typ die anderen aufruft. RE: Objekte verschiedener Kindklassen vergleichen - seuk - 27.06.2019 12:46 Okay, bleiben wir kurz bei dem was ich schon habe. Das läuft gänzlich ohne OOP und ich wollte versuchen es mit OOP zu optimieren. Ich habe derzeit folgendes Konstrukt: Modul A hat einen TypeDef Cluster "Modul A Settings" und beinhaltet n Werte verschiedener Typen Modul B hat einen TypeDef Cluster "Modul B Settings" und beinhaltet n Werte verschiedener Typen Der Settingseditor hat einen TypeDef Cluster "Settings" in dem die beiden Cluster der zwei Module sind. Dieser große Cluster mit den Settings aller Modulen wird mit Flattern to XML in eine Datei geschrieben und bei Programmstart von da gelesen. Der Settingseditor ist ein QMH und besitzt auf dem FP Bedienelemente vom Typ "Modul A Settings" und "Modul B Settings". Nun ändert der Anwender an den Bedienelementen etwas und drückt
Nun wollte ich erreichen, dass nur geänderte Werte an die Module kommuniziert werden und nicht die ganzen Cluster. Damit fing das Übel an :-) (27.06.2019 11:48 )th13 schrieb: Wenn du eine Referenz auf den Cluster hast, kannst du Mittels der Controls-Eigenschaft alle Elemente des Clusters in einer Schleife durchgehen. Und genau das war mein erster Versuch: Ich vergleiche zwei Cluster und bekomme ein Bool-Array. In einer Forschleife kann ich mit der Referenz auf Cluster -> Controls() an Label.Text kommen und muss anschließend eine CaseStructure verwenden, um darin das richtige VI aufzurufen, welches genau für die Kommunikation dieser Wertänderung zuständig ist. Wenn ich also eine Beschriftung ändere, muss ich den Case anpassen. Bei Erweiterungen muss ich einen Case hinzufügen. Das wollte ich generischer gestalten. Puh, weit ausgeholt, aber nun ist mein Problem vermutlich viel deutlicher, auch wenn es mit der Überschrift kaum noch etwas zu tun hat. (27.06.2019 11:45 )IchSelbst schrieb: 1. Zuerst bekommt das Modul von irgendwo her ("Herkunfsmodul") eine bestimmte Anzahl von Datenwerten, womöglich zusammengefasst als Cluster/Struct. Diese Daten sind dort, wo sie herkommen, z.B. Einstellparameter ("Settings")Korrekt, siehe oben: Mein Settingseditor ist in der Hierarchie meiner Module ganz unten, die GUI ganz oben, ModulA und ModulB dazwischen. Insofern ist er selbst das Herkunftsmodul der Settings für die anderen Module. (27.06.2019 11:45 )IchSelbst schrieb: 2. Diese Daten sollen angezeigt werden und vom Anwender geändert werden können: "SettingsEditor".korrekt (27.06.2019 11:45 )IchSelbst schrieb: 3. Sobald der Anwender sein OK für die geänderten Datenwerte gibt, sollen diese oder auch der ganze neue Datensatz zurück an das Herkunftsmodul.korrekt (27.06.2019 11:45 )IchSelbst schrieb: 4. Der Selbstzweck deines Programmmoduls ist also die Anzeige und Eingabe von Daten.korrekt (27.06.2019 11:45 )IchSelbst schrieb: So grob wie das hier steht, ist das ja ohne Typdefinition der Daten. Das geht aber nicht. Fazit: Es werden nicht die Datenwerte übergeben, sondern tatsächlich Datenwerte samt deren Typdefinition. Sowas ist möglich ("Laufzeit-Typ-Information"? RTTI?). Ein Variant z.B. kann das. Und eine Referenz auf Cluster auch. XML-Files auch. Text-basierte Sprachen auch. Das Problem ist, dass das Modul typ-abhängige Eingabeelemente braucht.In der lauffähigen Version habe ich das über die TypeDef Cluster der Module realisiert. Doch um das ganze flexibler zu gestalten, wollte ich mich davon verabschieden. Ich möchte die GUI möglichst abkoppeln, damit z.B. nicht alle Settings an einer Stelle im Programm vorgenommen werden müssen, um Settings auszublenden, um Abstraktion für den Anwender einzubauen (z.B. TemperaturRange: "High" statt 100-250°C) etc. Möglicherweise wird auch das noch zu Problemen führen. Ich hatte mir vorgestellt, dass der Settingseditor zukünftig vom GUI Modul eine Nachricht erhält und dieser kommuniziert die Werteänderung dann weiter an die Module. Die GUI sollte also "dumm" bleiben dürfen, damit die Logik "welche Werteänderung muss kommunizert werden?" im Settingseditor bleibt und nicht mehrfach implementiert werden muss. Ich dachte ich gebe jeglicher GUI also einfach auch den Zugriff auf alle Settings, in der GUI werden Änderungen vorgenommen und die kompletten Settings an den Settingseditor geschickt, der dann wie beschrieben weiter macht... (27.06.2019 11:45 )IchSelbst schrieb: Das Schöne an so Sachen wie .IsEqual oder .ToString, dass die ja in der objektorientierten Sprache systemimmanent im Datenobjekt sind. D.h. der Programmierer muss sich hier um nichts kümmern, muss sich also nicht um die Typverträglichkeit kümmern. In LabVIEW müsstest du eine Funktionalität generieren, die in objekt-orientierten System bereits integriert ist. Siehst du das auch so?Ich bin mir sicher, ob ich dich richtig verstehe. Ich kann zwar die LV Funktion "= Equal?" auf Objekte anwenden, doch wollte ich das nicht. Ich dachte ich schreibe eine eigene Funktion, die beispielsweise bei TemperatureRange die Min und Max Werte miteinander vergleicht und true zurück gibt, wenn dies der Fall ist. Ob das zweite Objekt dann eine Kopie oder Referenz ist, wäre mir gleich, da ich nur die Werte vergleichen wollte. RE: Objekte verschiedener Kindklassen vergleichen - IchSelbst - 27.06.2019 14:19 (27.06.2019 12:46 )seuk schrieb: Damit fing das Übel anSehe ich genauso. Ich sag dir kurz, wie mein Settingseditor aussieht:
Diese FGV kann man als einen Teil des Modules A (bzw. B etc) sehen. Die FGV ist also ein modul-internes Objekt. Alle Date, die in der FGV stehen, sind genau in dem Moment, indem sie in der FGV stehen, eben im Modul bekannt. => Ein Transfer ist nicht notwendig. Deine Frage: Jetzt fragst du nach dem Problem: Unterschied des Typs der Settingsparameter in den verschiedenen Modulen. Die Intension deiner Frage ist ja: Nach Möglichkeit ein Modul ("Settingsmodul") verwenden, das alle Settings-Typen kann - wobei keine Änderung am Settings-Modul gemacht werden soll. Meine Antwort: Deine Intension trifft genau meine: Ein Modul, das alles kann. Soll ohne Änderung, also nicht mit einer einzigen, wieder verwendbar sein. Problem ist, dass das tatsächlich sehr viele Probleme aufwirft. Daher habe ich meine FGV so standardisiert, dass bei der Implementation in ein anderes Modul tatsächlich nur minimale Anpassungen notwendig sind. Weil die wichtigsten Methoden (File-Schreiben/Lesen) Typ-unabhängig sind, geht das. Folgendes muss angepasst werden:
RE: Objekte verschiedener Kindklassen vergleichen - seuk - 27.06.2019 14:28 Ich habe mal ein Minimalbeispiel angehängt bei dem mein Versuch zu erkennen ist. Das Problem ist der Save-Case: Das obere Shift Register steht für die Settings im Modul, welche aktualisiert werden sollen. Das untere enthält die Änderungen an der GUI. Die beiden gilt es abzugleichen. [attachment=60125] Hier hole ich nun jedes einzelne Setting manuell aus dem Cluster, rufe die isEqual Methode (1.) seiner Kindklasse auf und bei einer Änderung wird der Wert aus der GUI-Kopie (2. - Get) in das obere Shiftregister kopiert (3. - Set). Wie kann ich das so lösen, dass im SaveCase nichts angepasst werden muss, wenn weitere Settings hinzukommen bzw. deren Namen oder Typen geändert werden? Das sollte doch mithilfe von Dynamic Dispatch möglich sein, indem ein Array der Elternklasse durchlaufen wird und eine konkretes VI einer Kindklasse aufgerufen wird, welches genau die drei Schritte enthält... RE: Objekte verschiedener Kindklassen vergleichen - IchSelbst - 27.06.2019 14:45 (27.06.2019 12:46 )seuk schrieb: Ich vergleiche zwei Cluster und bekomme ein Bool-Array. In einer Forschleife kann ich mit der Referenz auf Cluster -> Controls() an Label.Text kommen und muss anschließend eine CaseStructure verwenden, um darin das richtige VI aufzurufen, welches genau für die Kommunikation dieser Wertänderung zuständig ist. Wenn ich also eine Beschriftung ändere, muss ich den Case anpassen. Bei Erweiterungen muss ich einen Case hinzufügen.Genau. Solche Probleme treten auf. Daher wird bei mir immer der ganze Cluster hin und her geschoben. Hinweis: In LV-2017 gibt es mittlerweile sog. UID (Unique Identifier), die glaube ich manches vereinfachen. Umbenennungen sind dann kein Problem mehr - aber Löschungen! Zitat:Das wollte ich generischer gestalten.Jawohl! Mir ist da sofort das programmatische Erstellen von Anzeige/Bedienelementen zur Laufzeit in den Sinn gekommen. Leider kennt LV sowas nicht. Zitat:Puh, weit ausgeholt, aber nun ist mein Problem vermutlich viel deutlicher,Jetzt bin ich mir ziemlich sicher zu wissen was du willst. Zitat:Ich möchte die GUI möglichst abkoppeln,Sehr guter Wunsch. Den hab ich nämlich auch: Bei mir ist er alleine in der Trennung der Daten vom Frontpanel begründet. Das FP ist ein lästiges Übel, das man braucht, damit der Anwender was sieht und eingeben kann. Zitat:Ich hatte mir vorgestellt, ...Das klingt aber eher nach einen Diplomarbeit, als nach mal eben machen und im Forum Hilfe bekommen ... Ich bin noch am nachdenken ... |