Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#6

Re: Speichern von Baumstrukturen

  Alt 29. Sep 2003, 20:56
Hi,

Da ich selber schon so was gecodet habe will ich dir erklären wie ich es gemacht habe.
Die Grundbedingungen waren exakt die gleichen wie bei dir
- Node Klassen die für eigene Daten abgeleitet werden
- Node Klassen durften nicht von TComponent aber von TPersistent abgeleitet werden
- Nodes sollten sich per Delphi TComponent Streamingsystem speichern

Besonders der letzte Punkt war enorm wichtig, da ich wollte das man keienrlei explizite Sources programmieren sollte um published Properties zu speichern doer zu laden. Denoch sollte man über DefineProperties() eigene Speicher/Lade Methoden wie bei TComponent gewohnt programmieren können.

Somit sieht es verkürzt so aus:
Delphi-Quellcode:
type
  TNode = class(TPersistent)
  private
    FParent: TNode;
    FChilds: TList;
    FText: String;
    function GetCount: Integer; // FChilds.Count
    function GetChildren(Index: Integer): TNode; // FChilds[Index]
  protected
    procedure AssignTo(Source: TPersistent); override;
  public
    function ForEach(Callback: TNodeForeachFunc; Reverse: Boolean): TNode;
    function Attach(Index: Integer; Node: TNode; Absolute: Boolean): TNode;
    procedure SaveToStream(Stream: TStream); virtual;
    class function LoadFromStream(Node: TNode; Stream: TStream): TNode; virtual;
    property Count: Integer read GetCount;
    property Children[Index: Integer]: TNode read GetChildren; default;
    property Parent: TNode read FParent write SetParent;
    property Index: Integer read GetIndex;
  published
    property Text: String read FText write SetText;
  end;

  TMyTestNode = class(TNode)
  private
    FData: String;
    FValue: Integer;
    FMemory: TMemoryStream;
  protected
    procedure DefineProerties(Filer: TFiler); override;
  public
    property Memory: TMemoryStream read FMemory;
  published
    property Data: String read FData write FData;
    property Value: Integer read FValue write FValue default 12;
  end;
Eine TNode sieht also abstrahiert so wie oben aus.
Wichtig war mir das eben das Delphi Streaming System dafür benutzt wurde um
- eigene Properties mit DefineProperty/DefineBinaryPropery zu ermöglichen. In TMyTestNode würde die benutzt werden um FMemory zu speichern
- alle published Properties ohne zusätzlichen Code in Streams zu speichern, eben Delphi like.
- .Assign() und .AssignTo() benutzt werden um per temp. Streams und Delphis Streaming Nodes zuweisbar zu machen. D.h. Assign() und Assignto() von TNode wurden so implementiert das sie über .SaveToStream() und .LoadToStream() Nodes sich zu weisen. Dadurch muß bei Nachfahren von Tnode niemals mehr irgendwelche .Assign() Methoden überschrieben werden um eigene TNode Felder zuzuweisen. All das wird implizit durch .Assign()/.Assignto() über .SaveToStream()/.LoadFromStream() erledigt.
- trotzdem sollten die Nodes von Tpersistent abgeleitet sein, die im Delphi Streaming System NICHT ohne TComponent Kontainer benutzt werden können. Genau darin bestand die Schwierigkeit, denn TPersistent's können nur gespeuchert werden wenn sie als publishded Property einer TComponent benutzt werden. Ich erfand dann die Lösung indem TNode.SaveToStream() eine versteckte TNodeComponent helper Klasse benutzte. D.h. zu jeder Node im Baum wird temporär eine TNodeComponent erzeugt die eine published Property benutzte die die eigentlich TNode enthält. Somit konnt man auf die Vorzüge des Delphi Streamingssystems aufbauen. Eine Grundbedingung dabei war natürlich das meine TNodes schon in Delphi 1 bis heute in Delphi 7 ohne Änderungen funktionieren sollten, und auch tue'n.

Gruß hagen
  Mit Zitat antworten Zitat