Autor Beitrag
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mo 29.08.05 10:59 
Morgen!

Ich muss programmbedingt ein Objekt speichern, d.h. genauer gesagt eine Klasse, die von TObject abstammt. Das Problem: das Objekt hat zusätzlich zu seinen Eigenschaften auch "Unter"objekte. Wie kann ich das speichern? Und wie wieder laden? WriteComponent TFilestream scheidet aus, weil meine Klassen ja von TObject abstammen. Bin für alle Ideen offen :)

AXMD


Moderiert von user profile iconChristian S.: Topic aus CLX / Delphi Language (Object-Pascal) verschoben am Mo 29.08.2005 um 11:27
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 29.08.05 11:24 
Hallo!

Wie ich Dir schon per ICQ geasgt habe, würde ich das rekursiv machen! Du gibst jedem Objekt eine Methode SaveToStream(var s : TFilestream). Die sieht dann so aus:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure TaClass.SaveToStream(var s : TFilestream);
var
  i : Integer;
begin
  if s = nil then
    exit;

  //Teil 1: Eigene Daten
  s.Write(aVar, sizeOf(aVar));
  s.Write(anotherVar, sizeOf(anotherVar));

  //Teil 2: Daten von Fremdkomponenten
  for i:=0 to High(subObjects) do
    subObjects[i].SaveToStream(s);
end;

procedure TaClass.LoadFromStream(var s : TFilestream);
var
  i : Integer;
begin
  if s = nil then
    exit;

  //Teil 1: Eigene Daten
  s.Read(aVar, sizeOf(aVar));
  s.Read(anotherVar, sizeOf(anotherVar));

  //Teil 2: Daten von Fremdkomponenten
  for i:=0 to High(subObjects) do
    subObjects[i].LoadFromStream(s);
end;


Dadurch, dass jedes Objekt weiß, wievie Daten in Teil 1 stehen (zur Not am Anfang von Teil 1 mitspeichern), weiß es genau, zu welchem Punkt es an die anderen Objekte übergeben muss.

Ist jetzt ohne Delphi zur Hand zu haben geschrieben, aber von der Idee her sollte es gehen.

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mo 29.08.05 14:53 
Ich würde eine entsprechende Datenstruktur (z.B. Baum) definieren und die Daten rekursiv dort einfügen. So lässt sich das ganze am Schluss auch als XML Dokument (o.ä.) speichern.
Man muss auch darauf achten, dass man beim Laden die Unterobjekte auch wieder erstellen muss...
Sprint
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 849



BeitragVerfasst: Mo 29.08.05 15:32 
Ich bevorzuge bei sowas immer die Klassen TReader und TWriter. Mal ein Beispiel:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
unit Unit2;

interface

uses
  SysUtils, Classes;

type
  TMyClass = class(TObject)
  private
    FValueA: String;
    FValueB: Integer;
    procedure SaveValues(AFiler: TWriter);
    procedure LoadValues(AFiler: TReader);
  public
    property ValueA: String read FValueA write FValueA;
    property ValueB: Integer read FValueB write FValueB;
  end;

  TMyObject = class(TObject)
  private
    FMyClass: TMyClass;
  public
    constructor Create;
    destructor Destroy; override;
    procedure SaveToFile(const FileName: String);
    procedure LoadFromFile(const FileName: String);
    property MyClass: TMyClass read FMyClass write FMyClass;
  end;

implementation

{ TMyClass }

procedure TMyClass.LoadValues(AFiler: TReader);
begin
  FValueA := AFiler.ReadString;
  FValueB := AFiler.ReadInteger;
end;

procedure TMyClass.SaveValues(AFiler: TWriter);
begin
  AFiler.WriteString(FValueA);
  AFiler.WriteInteger(FValueB);
end;

{ TMyObject }

constructor TMyObject.Create;
begin
  inherited;
  FMyClass := TMyClass.Create;
end;

destructor TMyObject.Destroy;
begin
  FMyClass.Free;
  inherited;
end;

procedure TMyObject.LoadFromFile(const FileName: String);
var
  Handle: Integer;
  Stream: THandleStream;
  Filer: TReader;
begin
  Handle := FileOpen(FileName, fmOpenRead);
  if Handle <> -1 then
  begin
    Stream := THandleStream.Create(Handle);
    Filer := TReader.Create(Stream, 4096);
    try
      Filer.ReadSignature;
      if Filer.ReadIdent = ClassName then
        MyClass.LoadValues(Filer);
    finally
      Filer.Free;
      Stream.Free;
      FileClose(Handle);
    end;
  end;
end;

procedure TMyObject.SaveToFile(const FileName: String);
var
  Handle: Integer;
  Stream: THandleStream;
  Filer: TWriter;
begin
  Handle := FileCreate(FileName);
  if Handle <> -1 then
  begin
    Stream := THandleStream.Create(Handle);
    Filer := TWriter.Create(Stream, 4096);
    try
      Filer.WriteSignature;
      Filer.WriteIdent(ClassName);
      FMyClass.SaveValues(Filer);
    finally
      Filer.Free;
      Stream.Free;
      FileClose(Handle);
    end;
  end;
end;

end.

_________________
Ciao, Sprint.
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mo 29.08.05 15:38 
user profile icondelfiphan hat folgendes geschrieben:
Man muss auch darauf achten, dass man beim Laden die Unterobjekte auch wieder erstellen muss...


Eben das wird eines des größeren Probleme werden. Vor allem deshalb, weil 4 Kinderklassen von meiner Klasse abstammen, die alle "Unter"objekte sein können.

AXMD
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 29.08.05 15:53 
user profile iconAXMD hat folgendes geschrieben:
Eben das wird eines des größeren Probleme werden. Vor allem deshalb, weil 4 Kinderklassen von meiner Klasse abstammen, die alle "Unter"objekte sein können.
Um das hinzubekommen, könnte Dir dies helfen. Da instanziert eine Mutterklasse beim Laden von Klassen aus einer Datei immer die richtige Kindklasse. Arbeitet auch ganz gut mit dem zusammen, was ich oben geschrieben habe ;-)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mo 29.08.05 18:22 
Konnte das Problem dank Christians Ratschlägen und ein bisschen Experimentieren gut lösen :). Für alle die's interessiert: der Code hier. Im Anhang die komplette Unit um die Sache im Kontext zu sehen :)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TCircuitElementGroup.SaveToStream(var AStream: TFileStream);
var
  i: Integer;
begin
  inherited;
  i := Length(FElements);
  AStream.Write(i, SizeOf(i)); //Write number of subelements
  AStream.Write(FParallel, SizeOf(FParallel));
  for i := Low(FElements) to High(FElements) do //Write subelements to stream
    FElements[i].SaveToStream(AStream);
end;


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
function LoadFromStream(var AStream: TFileStream): TCustomCircuitElement;
var
  TempID, i: Integer;
  AValue: Double;
  AName: ShortString;
  AParallel: Boolean;
begin
  Result := nil//Initialize
  with AStream do begin
    Read(TempID, SizeOf(TempID)); //ID
    Read(AName, SizeOf(AName)); //Name
    Read(AValue, SizeOf(AValue)); //Value
    case TempID of
      1: Result := TResistor.Create(AValue);
      2: Result := TCapacitor.Create(AValue);
      3: Result := TCoil.Create(AValue);
      4begin
           Result := TCircuitElementGroup.Create;
           Read(TempID, SizeOf(TempID)); //Read number of children
           Read(AParallel, SizeOf(AParallel));
           (Result as TCircuitElementGroup).Parallel := AParallel;
           for i := 0 to TempID - 1 do
             (Result as TCircuitElementGroup).AddElement(LoadFromStream(AStream));
         end;
      end;
    Result.Name := AName;
    end;
end;


AXMD

//EDIT: Datei angehängt :)
Einloggen, um Attachments anzusehen!