Solved

Streaming TOwnedCollection descendant from flat file

Posted on 2003-12-12
8
591 Views
Last Modified: 2013-11-23
I have a TOwnedCollection descendant  that I am using (for my collection items). Can someone point me to some sample code for loading (streaming) my collection from a fla file.

Thanks, Tom.
0
Comment
Question by:tomcorcoran
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 8

Expert Comment

by:Cesario
ID: 9927100
Hi tom,


Procedure TForm1.FormCreate(..);
Begin
  RegisterClass ( YourCollection );
 RegisterClass ( your CollectionItemClass );  // registerClass (TMyCollItem);
End;


To load the Collection
ReadComponentResFile(FileName: string,YourCollectio)

To save it ( the Collection should be created before calling this functiuon):
procedure WriteComponentResFile( FileNam,yourCollection);

best Regards

Cesario
0
 

Author Comment

by:tomcorcoran
ID: 9927759
Thanks for the note. WriteComponentResFile looks for a TComponent descendant for "yourCollection", I want to pass a TownedCollection descendant. ANy ideas what I need to do? Cheers, tom.
0
 

Expert Comment

by:Engwi
ID: 9927828
Tom

What does the class declaration look like for your decendant.

Reading the file should be quite easy, just use the data returned with the add function in your class to add items to the collection.

Regards
 Engwi
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Accepted Solution

by:
Cesario earned 75 total points
ID: 9927994
How to implement TCollection.SaveToStream

procedure ReadCollection(s: TStream; c: TCollection);
var
  Reader: TReader;
begin
  Reader := TReader.Create(s, 1024);
  try
    Reader.ReadValue;  {collection marker}
    Reader.ReadCollection(c);
  finally
    Reader.Free;
  end;
end;
 
 
procedure WriteCollection(s: TStream; c: TCollection);
var
  Writer: TWriter;
begin
  Writer := TWriter.Create(s, 1024);
  try
    Writer.WriteCollection(c);
  finally
    Writer.Free;
  end;
end;


Now WriteCollection (your Collection  Var )
0
 

Author Comment

by:tomcorcoran
ID: 9928138
Engwi,
  TMyCollection = class(TOwnedCollection)
....sure the add gives me the TMyCollectionItem but I am trying to figure out how to stream the date to a file.....

Cesario I added :

procedure WriteFile(const FileName: string; Collection : TCollection);
  var
    AFile : TFileStream;
begin
  AFile := TFileStream.Create(FileName,fmCreate or fmOpenWrite);
  try
    WriteCollection(AFile,Collection);
  finally
    AFile.Free;
  end;
end;

procedure ReadFile(const FileName: string; Collection : TCollection);
  var
    AFile : TFileStream;
begin
  AFile := TFileStream.Create(FileName,fmOpenRead);
  try
    ReadCollection(AFile,Collection);
  finally
    AFile.Free;
  end;
end;

This works great, thanks. Note it works with or without the (single) RegisterClass(TMyCollection).

The resultant file has binary stuff in it and is not very pretty. How can I get it to produce neat output in the file like Delphi does with the dfm?

Thanks a lot,

Tom.


0
 
LVL 3

Assisted Solution

by:Stefaan
Stefaan earned 25 total points
ID: 9928183
Ok, here is a little sample, it contains a form and two buttons, one for writing out the Collection and one for reading in the Collection.

As you will see there is a descendant of an OwnedCollection there TTests with its CollectionItems TTest, and both will be streamed to a file and read back in.  The trick was to use a Componet Wrapper just like Borland did in the VCL ( see GridColumns of a TdbGrid ).

Here it is :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btnButton1: TButton;
    btnButton2: TButton;
    procedure btnButton1Click(Sender: TObject);
    procedure btnButton2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TTest = class( TCollectionItem )
  private
    FTestInteger: Integer;
    FTestString: String;
  public
    procedure Assign( Source : TPersistent ); override;

  published
    property TestString  : String  read FTestString  write FTestString;
    property TestInteger : Integer read FTestInteger write FTestInteger;
  end;

  TTests = class( TOwnedCollection )
  private
    FMyName: String;
  public
    procedure Assign( Source : TPersistent ); override;

    procedure LoadFromFile(const Filename: string);
    procedure LoadFromStream(S: TStream);

    procedure SaveToFile(const Filename: string);
    procedure SaveToStream(S: TStream);
  published
    property MyName : String read FMyName write FMyName;
  end;

  TCollectionWrapper = class( TComponent )
  private
    FTests : TTests;
  published
    property Tests : TTests read FTests write FTests;
  end;

var
  Form1: TForm1;

implementation

{$IFDEF CODESITE}
uses
  csIntf;
{$ENDIF}

{$R *.dfm}

{ TMyOwnedCollection }

procedure TTests.Assign(Source: TPersistent);
begin
  if ( Source is TTests ) then
  begin
    MyName := TTests( Source ).MyName;
  end;

  inherited;
end;

procedure TTests.LoadFromFile(const Filename: string);
var
  S: TFileStream;
begin
  S := TFileStream.Create(Filename, fmOpenRead);
  try
    LoadFromStream(S);
  finally
    S.Free;
  end;
end;

procedure TTests.LoadFromStream(S: TStream);
var
  Wrapper: TCollectionWrapper;
begin
  Wrapper := TCollectionWrapper.Create(nil);
  try
    Wrapper.Tests := TTests.Create( Self, TTest );
    S.ReadComponent( Wrapper);
    Assign(Wrapper.Tests);
  finally
    Wrapper.Tests.Free;
    Wrapper.Free;
  end;
end;

procedure TTests.SaveToFile(const Filename: string);
var
  S: TStream;
begin
  S := TFileStream.Create(Filename, fmCreate);
  try
    SaveToStream(S);
  finally
    S.Free;
  end;
end;

procedure TTests.SaveToStream(S: TStream);
var
  Wrapper: TCollectionWrapper;
begin
  Wrapper := TCollectionWrapper.Create(nil);
  try
    Wrapper.Tests := Self;
    S.WriteComponent(Wrapper);
  finally
    Wrapper.Free;
  end;
end;

{ TMyOwnedCollectionWrapper }

procedure TForm1.btnButton1Click(Sender: TObject);
var
  aTests : TTests;
  aTest  : TTest;
  lcv    : Integer;
begin
  aTests := TTests.Create( Self, TTest );
  aTests.MyName := 'Test';
  for lcv := 0 to 9 do
  begin
    aTest := TTest( aTests.Add );
    aTest.TestInteger := lcv;
    aTest.TestString  := IntToStr( lcv );
  end;
  aTests.SaveToFile( 'C:\Test.txt' );
  FreeAndNil( aTests );
end;

procedure TForm1.btnButton2Click(Sender: TObject);
var
  aTests : TTests;
  lcv    : Integer;
begin
  aTests := TTests.Create( Self, TTest );
  aTests.LoadFromFile( 'C:\Test.txt' );
{$IFDEF CODESITE}
  CodeSite.SendObject( 'aTests', aTests );
  for lcv := 0 to pred( aTests.Count ) do
  begin
    CodeSite.SendInteger( 'aTest[' + IntToStr( lcv ) + '].TestInteger', TTest(aTests.Items[ lcv ]).TestInteger );
    CodeSite.SendString( 'aTest[' + IntToStr( lcv ) + '].TestString', TTest(aTests.Items[ lcv ]).TestString );
  end;
{$ENDIF}
  FreeAndNil( aTests );
end;

{ TTest }

procedure TTest.Assign(Source: TPersistent);
begin
  if ( Source is TTest ) then
  begin
    Self.TestInteger := TTest( Source ).TestInteger;
    Self.TestString := TTest( Source ).TestString;
  end
  else
    inherited;
end;

end.
0
 
LVL 3

Expert Comment

by:Stefaan
ID: 9928218
bleh, too late again :-P
0
 

Author Comment

by:tomcorcoran
ID: 9928584
Sorry you were late Stefaan, I have however converted to yuor method, much cleaner than the TReader . TWriter method, thank you!

The end result is the same. Any way to make the output clean (like delphi with the dfm). I am going to use it as a quick and dirty way of populating a collection so would like a cleaner file than present.

Cheers, Tom.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …

729 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question