AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TCollection und TCollectionItem

Ein Thema von Jens Schumann · begonnen am 19. Mai 2004 · letzter Beitrag vom 2. Jun 2004
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#1

TCollection und TCollectionItem

  Alt 19. Mai 2004, 07:45
Hallo,
ich gebe an unserem örtlichen Gymnasium eine Informatik AG. Dort habe
ich gerade den Schülern gezeigt, wie man mit Hilfe von TCollection und
TCollectionItem sehr einfach Listen (auch n-dimensionale Listen) speichern kann.
Ich denke, der Code ist auch für die Code-Library interessant.

Das Verfahren nutzt das Delphi-Streamingsystem. Delphi selbst nutzt dieses Technik
um z.B. die Komponenteneigenschaften, die im OI editiert werden, in die dfm-Datei
zu speichern. Bei TStatusbar ist die Panels-Eigenschaft eine Nachfahre von TCollection.
Ein einzelnes Panel dieser Collection ist vom Type TCollectionItem. Alle published
Eigenschaften eines Panels werden beim speichern vom Streamingsystem erfasst.
Ganz automatisch - ohne unser zu tun. Interessant ist, wenn eine published Eigenschaft
von TCollectionItem eine TCollection ist wird auch diese automatisch gespeichert. Damit
hätten wir praktisch schon ein 2-dimensionales "Array" gespeichert. Das kann man beliebig
fortsetzten. Der Anhang enthält eine Powerpointdatei. Darin habe ich versucht es graphisch
darzustellen.

Aber jetzt zum Beispielprogramm:
Das Programm hat ein TEdit, 2 TListBoxen und 2 TButtons.
Über das TEdit kann man Einträge hinzufügen (auf Enter drücken). Damit werden automatisch zu jedem Eintrag 5 Zahlen hinzugefügt (2. TListBox). Damit haben wir eine 2-dimensionale Struktur.
Zu jedem Eintrag (TAddressItem) gehören 5 Zahlen (TNumber). Die können jetzt gespeichert
und geladen werden.

TAddressItem entspricht einem Eintrag. Jedes TAddressItem hat in seiner published Abschnitt
eine Eigenschaft vom Type TNumbers. TNumbers ist ein Nachfahre von TCollection und verwaltet
die einzelnen TNumber (also die o.g. 5 Zahlen zu jedem Eintrag).

Jetzt kommt ein äußerst interessanter Punkt:
Wenn die published Eigenschaften von einem TCollectionItem (hier TAddressItem und TNumber)
erweitert werden, können die alten Datein immer noch gelesen werden. Die neuen Eigenschaft
dann mit Null initialisiert !!!!!!!!!!!!!
Das entspricht einer Änderung des Dateiformats. Das ist mit typisierten Dateien nicht möglich.

Die unit collection.pas enthält den interessanten Code.
Angehängte Dateien
Dateityp: zip collection.zip (195,1 KB, 104x aufgerufen)
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#2

Re: TCollection und TCollectionItem

  Alt 23. Mai 2004, 00:45
Moin.

Ja mit collection und dem streaming system kann man lustige sachen machen. Hab mich auch mal drann vergriffen, hab aber das 'owner' objekt nur in den stream gefaked und nicht extra als dummi erzeugt und dann direkt mit WriteCollection gearbeitet.

Vielleicht interssiert es dich ja: http://www.delphi-forum.de/viewtopic.php?t=18605

Was ich auch einen sehr interessanten aspekt des streaming systems finde, ist die möglichkeit dynamische binäre properties zu definieren


PS: Insbesondere wäre für dich vielleicht die möglichkeit von nutzen, den binären DFM-strom in das text-DFM format zu konvertieren, das macht die ganze sache schön lesbar un editierbar...kennt man ja.
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#3

Re: TCollection und TCollectionItem

  Alt 23. Mai 2004, 07:23
@maximov: GUter Tip - werde ich mir mal reinziehen.
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#4

Re: TCollection und TCollectionItem

  Alt 26. Mai 2004, 13:26
@maximov: Sehr guter Vorschlag. Wenn man auf die Option verzichtet die Datei im Textformat zu speichern und die Code auf das notwendigste reduziert ist Dein Vorschlag besser als meiner.
Dadurch, dass ich den Umweg über ein TComponent gehe sind die Daten in den Items für eine Schrecksekunde doppelt im Speicher. Einmal in der Collection und über Assigen in der Items property des Dummies. Für das Textformat schreibst Du erst mal alles in einen TMemorystream. In dem Moment sind die Daten ebenfalls doppelt vorhanden.

Wenn man jetzt aber auf TMemoryStream verzichtet und über TWriter/TReader direkt in den Stream schreibt sind die Daten nicht doppelt vorhanden. Wie gesagt, wenn auf das Textformat verzichtet
werden kann finde ich diese Lösung besser.

Vielen Dank für die Anregung !!!

Delphi-Quellcode:
unit CollectionExt;

interface

Uses SysUtils, Classes;

Type

  TExtCollection = class(TCollection)
  private
    function GetFormatSignature: String;
  public
    procedure SaveToFile(const Filename : TFilename);
    procedure SaveToStream(Stream : TStream);
    procedure LoadFromFile(const Filename : TFilename);
    procedure LoadFromStream(Stream : TStream);
  end;

implementation

const
  iFilerBufferSize = 4096;

{ TExtCollection }

function TExtCollection.GetFormatSignature: String;
begin
  Result := ItemClass.ClassName;
end;

procedure TExtCollection.LoadFromFile(const Filename: TFilename);
var
  FileStream : TFileStream;
begin
  Clear;
  FileStream:=TFileStream.Create(Filename,fmOpenRead);
  Try
    LoadFromStream(FileStream);
  Finally
    FileStream.Free;
    end;
end;

procedure TExtCollection.LoadFromStream(Stream: TStream);
var
  Reader : TReader;
begin
  Reader:=TReader.Create(Stream,iFilerBufferSize);
  Try
    Reader.ReadValue;
    Reader.ReadCollection(Self);
  Finally
    Reader.Free;
    end;
end;

procedure TExtCollection.SaveToFile(const Filename: TFilename);
var
  FileStream : TFileStream;
begin
  FileStream:=TFileStream.Create(Filename,fmCreate);
  Try
    SaveToStream(FileStream);
  Finally
    FileStream.Free;
    end;
end;

procedure TExtCollection.SaveToStream(Stream: TStream);
var
  Writer : TWriter;
begin
  Writer:=TWriter.Create(Stream,iFilerBufferSize);
  Try
    Writer.WriteCollection(Self);
  Finally
    Writer.Free;
    end;
end;

end.
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#5

Re: TCollection und TCollectionItem

  Alt 26. Mai 2004, 13:55
Hi.

Mir geht es natürlich nicht um besser oder schlechter (*man kann ja nur von einander lernen*) sondern um einen ideenaustausch *g*

Mir gefällt das mit der dummy-compo eigentlich ganz gut UND du müsstest auch nicht mit assign arbeiten, sondern könntest direkt die referenz zuweisen. Der vorteil wäre dann auch, das man im container noch zusätzliche properties definieren kann, die nicht in jedem item auftauchen dürfen/sollten - quasi globale infos...

Was die text-konvertierung angeht, kann man es sicherlich auch so machen, das beim binären speichern direkt in den ziel-stream gespeichert wird und nur beim text-format ein puffer benutzt wird (was bei mir momentan leider nicht der fall ist). Der grosse vorteil wäre, das man die daten prüfen und editieren kann, solange man entwickelt, und wenn man das programm ausliefert, konvertiert man alles ins binär-format, womit dann jegliche redundanzen verschwinden.

mfg.
max.
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#6

Re: TCollection und TCollectionItem

  Alt 26. Mai 2004, 16:46
Zitat von maximov:
Mir gefällt das mit der dummy-compo eigentlich ganz gut UND du müsstest auch nicht mit assign arbeiten, sondern könntest direkt die referenz zuweisen. Der vorteil wäre dann auch, das man im container noch zusätzliche properties definieren kann, die nicht in jedem item auftauchen dürfen/sollten - quasi globale infos...
Wenn ich es richtig verstehe, sollen
über diesen Weg die published properties der TCollection gespeichert werden. Leider bekomme ich das nicht hin. Wie meinst Du das genau?

Die property Collectionname in TAddressItems wird nicht mitgespeichert
Delphi-Quellcode:
unit Collection;

interface

uses SysUtils, classes;

Type

   {TNumber repräsentiert je einen Eintrag in TNumbers}
   TNumber = class(TCollectionItem)
   private
    FNumber : Integer;
   public
     procedure Assign(Source : TPersistent); override; // muss überschrieben werden
   published
     property Number : Integer read FNumber write FNumber;
   end;

   TNumbers = class(TCollection)
   private
    function GetItem(X: Integer): TNumber;
    procedure SetItem(X: Integer; const Value: TNumber);
   public
     constructor Create;
     function Add : TNumber;
     property Items[X : Integer] : TNumber read GetItem write SetItem; default;
   end;

   {TAddressItem repräsentiert je einen Eintrag in TAddressItems
    Numbers ist hier ebenfalls ein Collection. Numbers wird
    automatisch gespeichert !!!}

   TAddressItem = class(TCollectionItem)
   private
    FFirstname : String;
    FNumbers : TNumbers;
   public
     constructor Create(Collection: TCollection); override;
     destructor Destroy; override;
     procedure Assign(Source : TPersistent); override; // muss überschrieben werden
   published
     property Firstname : String read FFirstname write FFirstname;
     property Numbers : TNumbers read FNumbers write FNumbers;
   end;

   {Das ist unsere Basisliste}
   TAddressItems = class(TCollection)
   private
    FCollectionName : String;
    function GetItem(X: Integer): TAddressItem;
    procedure SetItem(X: Integer; const Value: TAddressItem);
   public
     constructor Create;
     procedure Assign(Source : TPersistent); override;
     function Add : TAddressItem;
     procedure SaveToFile(const Filename : TFilename);
     procedure LoadFromFile(const Filename : TFilename);
     procedure SaveToStream(Stream : TStream);
     procedure LoadFromStream(Stream : TStream);
     property Items[X : Integer] : TAddressItem read GetItem write SetItem; default;
   published
     property CollectionName : String read FCollectionName write FCollectionName;
   end;

   {TAddressDummy ist ein Dummy, der nur benötigt wird, um
    TAddressItems zu speichern. Siehe TAddressItems.SaveToStream.
    Da das Streamingsystem erst ab TComponent greift brauchen wir
    hier diesen Dummy}

   TAddressDummy = class(TComponent)
   private
     FItems : TAddressItems;
   published
     property Items : TAddressItems read FItems write FItems;
   end;

implementation

{ TAddressItem }

procedure TAddressItem.Assign(Source: TPersistent);
begin
  If Source is TAddressItem then
    begin
    FFirstname:=TAddressItem(Source).Firstname;
    FNumbers.Assign(TAddressItem(Source).Numbers);
    end
      else
        inherited Assign(Source);
end;

constructor TAddressItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FNumbers:=TNumbers.Create;
end;

destructor TAddressItem.Destroy;
begin
  FNumbers.Free;
  inherited Destroy;
end;

{ TAddressItems }

function TAddressItems.Add: TAddressItem;
begin
  Result:=inherited Add as TAddressItem;
end;

constructor TAddressItems.Create;
begin
  inherited Create(TAddressItem);
end;

function TAddressItems.GetItem(X: Integer): TAddressItem;
begin
  Result:=inherited GetItem(X) as TAddressItem;
end;


procedure TAddressItems.SaveToFile(const Filename: TFilename);
var
  FileStream : TFileStream;
begin
  FileStream:=TFileStream.Create(Filename,fmCreate);
  Try
    SaveToStream(FileStream);
  Finally
    FileStream.Free;
    end;
end;

procedure TAddressItems.LoadFromFile(const Filename: TFilename);
var
  FileStream : TFileStream;
begin
  Clear;
  FileStream:=TFileStream.Create(Filename,fmOpenRead);
  Try
    LoadFromStream(FileStream);
  Finally
    FileStream.Free;
    end;
end;

procedure TAddressItems.SaveToStream(Stream: TStream);
var
  AddressDummy : TAddressDummy;
begin
  AddressDummy:=TAddressDummy.Create(Nil);
  Try
    AddressDummy.Items:=Self;
    Stream.WriteComponent(AddressDummy);
  Finally
    AddressDummy.Free;
    end;
end;

procedure TAddressItems.LoadFromStream(Stream: TStream);
var
  AddressDummy : TAddressDummy;
begin
  AddressDummy:=TAddressDummy.Create(Nil);
  Try
    AddressDummy.Items:=Self;
    Stream.ReadComponent(AddressDummy);
  Finally
    AddressDummy.Free;
    end;
end;

procedure TAddressItems.SetItem(X: Integer; const Value: TAddressItem);
begin
  inherited SetItem(X,Value);
end;


procedure TAddressItems.Assign(Source: TPersistent);
begin
  If Source is TAddressItems then
    FCollectionName:=TAddressItems(Source).CollectionName
      else
        inherited Assign(Source);
end;


{ TNumber }

procedure TNumber.Assign(Source: TPersistent);
begin
  If Source is TNumber then
    begin
    FNumber:=TNumber(Source).Number;
    end
      else
        inherited Assign(Source);
end;

{ TNumbers }

function TNumbers.Add: TNumber;
begin
  Result:=inherited Add as TNumber
end;

constructor TNumbers.Create;
begin
  inherited Create(TNumber);
end;

function TNumbers.GetItem(X: Integer): TNumber;
begin
  Result:=inherited GetItem(X) as TNumber;
end;

procedure TNumbers.SetItem(X: Integer; const Value: TNumber);
begin
  inherited SetItem(X,Value);
end;

end.
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Benutzerbild von Jens Schumann
Jens Schumann

Registriert seit: 27. Apr 2003
Ort: Bad Honnef
1.644 Beiträge
 
Delphi 2009 Professional
 
#7

Re: TCollection und TCollectionItem

  Alt 26. Mai 2004, 16:56
Hallo maximov,
die einzige Lösung die mir gerade eingefallen ist wäre folgende:
Delphi-Quellcode:
   TAddressDummy = class(TComponent)
   private
     FItems : TAddressItems;
     FCollectionname : String;
   public
   published
     property Items : TAddressItems read FItems write FItems;
     property Collectionname : String read FCollectionname write FCollectionname;
   end;

procedure TAddressItems.SaveToStream(Stream: TStream);
var
  AddressDummy : TAddressDummy;
begin
  AddressDummy:=TAddressDummy.Create(Nil);
  Try
    AddressDummy.Items:=Self;
    AddressDummy.Collectionname:=FCollectionname;
    Stream.WriteComponent(AddressDummy);
  Finally
    AddressDummy.Free;
    end;
end;

procedure TAddressItems.LoadFromStream(Stream: TStream);
var
  AddressDummy : TAddressDummy;
begin
  AddressDummy:=TAddressDummy.Create(Nil);
  Try
    AddressDummy.Items:=Self;
    Stream.ReadComponent(AddressDummy);
    FCollectionname:=AddressDummy.Collectionname;
  Finally
    AddressDummy.Free;
    end;
end;
Aber dem Dummy ebenfalls eine Collectionname property zu spendieren finde ich irgendwie doof.
I come from outer space to save the human race
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#8

Re: TCollection und TCollectionItem

  Alt 27. Mai 2004, 00:43
Zitat von Jens Schumann:
Zitat von maximov:
Mir gefällt das mit der dummy-compo eigentlich ganz gut UND du müsstest auch nicht mit assign arbeiten, sondern könntest direkt die referenz zuweisen. Der vorteil wäre dann auch, das man im container noch zusätzliche properties definieren kann, die nicht in jedem item auftauchen dürfen/sollten - quasi globale infos...
Wenn ich es richtig verstehe, sollen
über diesen Weg die published properties der TCollection gespeichert werden. Leider bekomme ich das nicht hin. Wie meinst Du das genau?

Die property Collectionname in TAddressItems wird nicht mitgespeichert
....
Ja du hast es erfasst! Das ist in der tat ein problem, da das streaming-system die collection-klasse gesondert behandelt und es somit nur als container für items identifiziert Aber dazu fällt mir bestimmt noch was ein ...wär halt cool weil man damit das klassische array problem aufbrechen könnten und somit nicht nur serielle daten des gleichen typs permanent verfügbar machen könnte! Mann kann natürlich gleich ein TComponent als ausgangspunkt nehmen, was aber nicht halb so elegant wäre, da sich damit ja sowiso hierarchische strukturen streamen lassen ...mal sehn
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
Benutzerbild von mirage228
mirage228

Registriert seit: 23. Mär 2003
Ort: Münster
3.750 Beiträge
 
Delphi 2010 Professional
 
#9

Re: TCollection und TCollectionItem

  Alt 27. Mai 2004, 12:34
Hi,

wer die Sourcen hat, kann sich die Implementierung von TWebDispatcher in der Unit HTTPApp anschauen. Dort ist es so gelöst, dass a) die Collection im OI angezeigt und b) automatisch mit dem DFM gespeichert wird.

mfG
mirage228
David F.

May the source be with you, stranger.
PHP Inspection Unit (Delphi-Unit zum Analysieren von PHP Code)
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#10

Re: TCollection und TCollectionItem

  Alt 27. Mai 2004, 13:37
Zitat von mirage228:
Hi,

wer die Sourcen hat, kann sich die Implementierung von TWebDispatcher in der Unit HTTPApp anschauen. Dort ist es so gelöst, dass a) die Collection im OI angezeigt und b) automatisch mit dem DFM gespeichert wird.

mfG
mirage228
Dazu muss man kein prophet sein ...dafür sind collections ja auch da, wir versuchen nur grad zu klären, ob wir sie für unsere eigenen, dunklen zwecke missbrauchen können, bzw. erweitern und das mit möglichst hoher informations-effiziens und service-fähigkeiten.

@Jens:Ich seh grad, dass TCollection von TObject abstammt womit wir wohl deren published-props vergessen können, da sie keine RTTI besitzen...verdammt wäre ja auch zu schön gewesen!

Wie wäre es mit einem 'streaming-provider' der von TComponent abgeleitet ist und standartmässig die items property hat, wo man dann soviele properties hinzufügen kann, wie man will?
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 01:33 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