Solved

Streaming TOwnedCollection descendant from flat file

Posted on 2003-12-12
8
585 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
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 8

Expert Comment

by:Cesario
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 8

Accepted Solution

by:
Cesario earned 75 total points
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:tomcorcoran
Comment Utility
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
Comment Utility
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
Comment Utility
bleh, too late again :-P
0
 

Author Comment

by:tomcorcoran
Comment Utility
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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

772 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now