AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Komponenten in Stream speichern und wieder herstellen
Thema durchsuchen
Ansicht
Themen-Optionen

Komponenten in Stream speichern und wieder herstellen

Ein Thema von stahli · begonnen am 16. Jan 2008 · letzter Beitrag vom 17. Jan 2008
Antwort Antwort
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#1

Komponenten in Stream speichern und wieder herstellen

  Alt 16. Jan 2008, 17:15
{
Einfach nur mal zu Diskussion ein Versuch der Darstellung meines Lösungsansatzes.
Für Profiprogrammierer sicher langweilig
Für Anfänger vielleicht interessant
Möglicherweise auch völlig falsch, weil man´s ganz anders macht
}

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:
Data1.Vorname := 'André'
Data1.Nachname := 'Stahl';
Visual1.Data := Data1;
Visual2.Data := Data1;
Beide visuellen Komponenten zeigen dann Änderungen von Data1 sofort an.

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:
Data1.StreamId = 100
Visual1.StreamId = 500
Visual1.DataStreamId = 100
Visual2.StreamId = 501
Visual2.DataStreamId = 100
Nach dem Einlesen des Streams durchsucht eine globale Prozedur die gesamte Application nach Komponenten, denen noch Komponentenadressen zugeordnet werden müssen.
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
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#2

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 15:28
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.
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#3

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 16:26
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
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#4

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 16:33
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 ?
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#5

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 16:40
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
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#6

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 16:49
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....
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#7

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 17:20
aus der Hilfe
Zitat:
Der Typ TComponentClass ist die Metaklasse für TComponent. Er enthält die Klassenreferenz für TComponent oder eines seiner Nachkommen.
Deine Komponenten dürften ja alle von TComponent abgeleitet sein.

Dann müsste zum ERZEUGEN der Komponente folgendes funktionieren:
Delphi-Quellcode:
var
  NewComponent: TComponent;

...
  NewComponent := TComponentClass(GetClass(ComponentNameAusDemStream)).Create(Self);
// NewComponent.MeineDatenLaden;
...
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.

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:
if ExistProcedure(NewComponent, 'MeineDatenLesen') then
  ExecuteProcedure(NewComponent, 'MeineDatenLesen');
Das würde mich auch freuen...

stahli
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#8

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 17:24
Natürlich gibts das. Die Methoden müssen Published sein, dann kann man MethodAddress verwenden.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
mimi

Registriert seit: 1. Dez 2002
Ort: Oldenburg(Oldenburg)
2.008 Beiträge
 
FreePascal / Lazarus
 
#9

Re: Komponenten in Stream speichern und wieder herstellen

  Alt 17. Jan 2008, 19:02
Zitat:
Deine Komponenten dürften ja alle von TComponent abgeleitet sein.
Nein sie sind direkt von TObject Abgeleitet. Weil es keine Komponenten für Lazarus oder Delphi sind.

bzw. ich schreibe gerade eine eigene GUI, die auf meiner 2D Engine Basiert.....
Michael Springwald
MFG
Michael Springwald,
Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:43 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz