![]() |
Komponenten in Stream speichern und wieder herstellen
{
Einfach nur mal zu Diskussion ein Versuch der Darstellung meines Lösungsansatzes. Für Profiprogrammierer sicher langweilig :zwinker: Für Anfänger vielleicht interessant :stupid: Möglicherweise auch völlig falsch, weil man´s ganz anders macht :shock: } Hallo alle, ich habe Datenkomponenten erstellt, die Daten verwalten, Berechnungen durchführen und miteinander "kommunizieren". Dazu gibt es visuelle Komponenten, die diese Daten anzeigen. Visuellen Komponenten kann eine Datenkomponente zugeordnet werden. Die Datenkomponente registriert dabei automatisch alle betreffenden visuellen Komponenten in einer TList und informiert diese bei Datenänderungen. Datenänderungen können natürlich auch über die visuellen Komponenten selbst durchgeführt werden.
Delphi-Quellcode:
Beide visuellen Komponenten zeigen dann Änderungen von Data1 sofort an.
Data1.Vorname := 'André'
Data1.Nachname := 'Stahl'; Visual1.Data := Data1; Visual2.Data := Data1; Die Datenkomponenten können ihre Daten in einen Stream speichern und wieder laden. Die visuellen Komponenten können ihre Position und den "Zeiger auf Data" in einen Stream speichern und wieder laden. Da Visual1.Data ja eine Adresse auf Data1 ist, bringt es aber nichts, diese direkt in den Stream zu speichern. Beim Laden der Daten aus einem Stream wird ja Data1 neu erzeugt und liest dann erst seine Daten ein. Die Speicheradresse ist dann eine völlig andere, als zum Zeitpunkt des Speicherns in den Stream. Daher mache ich folgendes: Vor dem Speichern der Daten setze ich eine globale Variable GStreamId auf 0; Beim Speichern jeder Komponente erhöht diese GStreamId um 1 und speichert zuerst diesen Wert und danach ihre eigenen Daten. Data1 würde als StreamId z.B. 100 schreiben (danach seine Daten). Visual1 würde z.B. 500 schreiben und zur Referenzierung auf Data noch die 100 (danach seine Position). Visual2 würde z.B. 501 schreiben und zur Referenzierung auf Data noch ebenfalls die 100 (danach seine Position). Nach dem Speichervorgang ist GStreamId unwichtig und wird auf 0 zurückgesetzt. Ebenso die temporär vergebenen StreamId´s der Daten- und visuellen Komponenten. Beim Laden aus dem Stream verfahre ich so: Die Komponenten werden erzeugt und laden sich Ihre "StreamId" und ihre zugehörigen Daten (die Komponenten befinden sich jetzt an einer beliebigen Speicheradresse). Anstelle von Zeigern auf die Datenkomponenten merken sich die visuellen Komponenten erst einmal nur die zugehörigen aus dem Stream gelesenen StreamId der gewünschten Datenkomponente. Zitat:
Hier wird nun zuerst Visual1 gefunden, deren DataStreamId = 100 ist. Eine globale Funktion durchsucht nun wiederum die gesamte Application nach einer Datenkomponente, deren StreamId = 100 ist und liefert deren Speicheradresse zurück. Diese wird Visual1.Data zugewiesen und Visual1.DataStreamId auf 0 gesetzt. Das gleiche erfolgt auch für Visual2, womit wieder alle Datenkomponenten ihren visuellen Komponenten zugeordnet sind (die Registrierung der visuellen Komponenten in den Datenkomponenten erfolgt hier wieder automatisch wie oben beschrieben). (In meinem Projekt können auch Datenkomponenten wieder andere Datenkomponenten enthalten und die Beziehungen in einem Stream abspeichern.) Nach dem Einlesen des Streams ist GStreamId wieder unwichtig und wird auf 0 zurückgesetzt. Ebenso auch wieder die temporär vergebenen StreamId´s der Daten- und visuellen Komponenten. Ich gehe davon aus, dass die IDE dies ähnlich erledigt, die Komponenten jedoch anhand des Komponentennamens sucht. In meinem Projekt werden jedoch die gesamten Stream-relevanten Komponenten dynamisch erzeugt und sind nicht über einen eindeutigen Namen identifizierbar. Ich möchte/kann auch keine automatischen Namen "DataName12345" o.ä. vergeben, da ich ggf. auch "Sub-Komponenten" aus einem eigenen Stream lesen möchte. Es darf dann ja nicht vorkommen, dass ein bereits in der Application vorhandener automatisch vergebener Name noch einmal benutzt wird. Mit meiner Lösung lässt sich eine eindeutige Beziehung der Komponenten untereinander zuverlässig realisieren, allerdings nur während dem Speichern in einen Stream bzw. beim Lesen aus dem Selben. Nach dem Einlesen werden die temp. StreamId´s nicht mehr benötigt und verworfen. Die gesamte Datenlogik und die Daten selbst werden in den Datenkomponenten verwaltet. Die Datenmengen sind nicht sehr groß, aber die Beziehungen recht komplex. Eine Datenbank erschien mir dann doch eher ungeeigneter. Meinungen? Beschwerden? Fragen? stahli |
Re: Komponenten in Stream speichern und wieder herstellen
Ein Interessantes Problem was du da beschreibst bzw. gelöst hast.
ich hatte selbst Probleme Damit bei meinem Paint2 Projekt. Dort hatte ich z.b. folgende Objekte: TLine, TVierEck TKreis Davon hatte ich in meiner ObjectLsite verschiedene..... mir ist leider nur ein Weg eingefallen: Beim einlesen aus einer TextDatei muss ich schauen; ist der KlassenTyp TLine dann installisiere eine TLine und soweiter. ist also ein gewisser Aufwand um ein neue Klasse hinzuzufügen. Meine frage währe jetzt, wie genau löst du das Problem... ? das habe ich noch nicht richtig verstanden... meine Datei sahr dann z.b. so aus: Typ, Name, Left, Top, Right, Bottom, Farbe und soweiter.... Der nachteil ist halt das immer die Lade Funktion angepasst werden muss, wenn eine neue Klasse dazu kommt. |
Re: Komponenten in Stream speichern und wieder herstellen
Hi mimi,
Du beziehst Dich eigentlich nicht ganz auf mein Thema: Du willst wieder Objekte erzeugen, die dem Typ entsprechen, deren Namen Du abgespeichert hast. Ich will dagegen nach dem Lesen aus dem Stream ursprüngliche Zeiger auf andere Komponenten wiederherstellen... Lösung für Dich (am Besipiel für Komponenten, die von TVCustom abgeleitet sind):
Delphi-Quellcode:
// Deklaration der Komponente:
TVCustom = class(TsPanel) ... end; TVCustomClass = class of TVCustom;
Delphi-Quellcode:
// laden und erzeugen
// Stream und Reader werden der Funktion übergeben, dadurch kann die Funktion flexibel eingesetzt werden procedure TMyData.LoadFromFileStream(S: TFileStream; R: TReader); var CN: String; NewVCustom: TVCustom; OldVisible: Boolean; begin LoadingMode := True; Irgendwas1 := R.ReadInteger; Irgendwas2 := R.ReadInteger; UndSoWeiter := R.ReadInteger; UndSoFort := R.ReadInteger; R.ReadListBegin; while (not R.EndOfList) do begin CN := R.ReadString; NewVCustom := TVCustomClass(GetClass(CN)).Create(Self); NewVCustom.LoadFromFileStream(S,R); // liest jetzt seine Daten ein VItems.Add(NewVCustom); // wird in die Liste aufgenommen NewVCustom.Left := ...; NewVCustom.Top := ...; NewVCustom.Parent := ..; end; R.ReadListEnd; DataChanged; // registrierte visuelle Komponenten werden beauftragt sich neu zu zeichnen IsChanged := False; // keine ungespeicherten Änderungen vorhanden LoadingMode := False; end; In dem Fall ist es Dir ja egal, an welcher Speicheradresse die neu erzeugten Komponenten abgelegt sind. Die Adressen sind jetzt natürlich völlig andere als beim Speichern in den Stream. Nun stell Dir vor, jede Deiner Linien hat einen Zeiger auf eine andere Linie (bzw. auf deren Speicheradresse). Dann passen diese Zeiger nach dem Lesen aus dem Stream natürlich nicht mehr, da die erzeugten Komponenten irgendwo im Speicher beliebig angelegt werden. Ich habe jetzt eine Möglichkeit gesucht, die neue und jetzt gültige Speicheradresse der "eigentlich gemeinten" Komponente (also im Beispiel der Folge-Linie) zu ermitteln und zuzuordnen. stahli |
Re: Komponenten in Stream speichern und wieder herstellen
naja im Prinzip haben wir das gleiche Probleme, nur wir gehen es beide anders an...
Aber dein Weg ist Praktischer, wenn ich ihn verstehen würde... NewVCustom := TVCustomClass(GetClass(CN)).Create(Self); diese Zeile Installisiert eine z.b Line ? oder eine Standard Komponente ? |
Re: Komponenten in Stream speichern und wieder herstellen
CN ist der ClassName, der aus dem Stream gelesen wurde.
GetClass (Unit TypInfo) ermittelt die Klasse. Davon wird eine Instanz erzeugt und der Variablen zugewiesen. Meine betreffenden Komponenten sind alle von TVCustom abgeleitet. Daher funktioniert das mit TVCustomClass wunderbar. Wie man´s mit unterschiedlichen Klassen oder Standardkomponenten macht kann ich nicht sagen. :? stahli |
Re: Komponenten in Stream speichern und wieder herstellen
aber du weisst was ich meine oder ?
Ich habe jetzt mehrer Klasse z.b. TplListbox, TplLabel, TplPanel, TplEdit das sind jetzt meine eigenen Klassen, und die möchte ich jetzt abspeichern... ohne immer zu prüfen ob CLassenTyp = TPlListbox ist wenn ja erstelle eine Listbox das soll er Automatisch machen wie bei Delphi/Lazarus edit: alle diese Klassen sind natürlich von einer Bases Klasse abgeleitet.... |
Re: Komponenten in Stream speichern und wieder herstellen
aus der Hilfe
Zitat:
Dann müsste zum ERZEUGEN der Komponente folgendes funktionieren:
Delphi-Quellcode:
Hier wird es schwierig. TComponent hat keine Methode MeineDatenLaden. TComponent kann sich in einen Stream speichern und aus einem Stream laden aber das entspricht nicht Deiner individuellen Schreib- und Lesemethode.
var
NewComponent: TComponent; ... NewComponent := TComponentClass(GetClass(ComponentNameAusDemStream)).Create(Self); // NewComponent.MeineDatenLaden; ... Wenn Du hier für jede Komponente eigene Funktionen benutzen willst TplLabel.MeineDatenSchreiben; TplLabel.MeineDatenLesen; TplPanel.MeineDatenSchreiben; TplPanel.MeineDatenLesen; wird Dir wohl nichts anderes übrig bleiben, als dies für jede Klasse explizit zu veranlassen. Es sei denn, es gäbe eine Funktion wie...
Delphi-Quellcode:
Das würde mich auch freuen...
if ExistProcedure(NewComponent, 'MeineDatenLesen') then
ExecuteProcedure(NewComponent, 'MeineDatenLesen'); stahli |
Re: Komponenten in Stream speichern und wieder herstellen
Natürlich gibts das. Die Methoden müssen Published sein, dann kann man MethodAddress verwenden.
|
Re: Komponenten in Stream speichern und wieder herstellen
Zitat:
bzw. ich schreibe gerade eine eigene GUI, die auf meiner 2D Engine Basiert..... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz