Solved

TCollection & TCollectionItem -> Help Please...

Posted on 2002-04-18
15
658 Views
Last Modified: 2010-04-04
Hi,
I havent really worked with TCollection or TCollectionItem before but Im trying to define a persistant structure using TCollection and TCollectionItem. I then write/read this "component" to/from a file using the Write/ReadComponent method.

Please find my code below.
1. It seems to work fine when Im writing it to a file, but when I try to read it back, I get a runtime error.

2. The writing and reading of the component works fine if I remove the ObjectContainer property from the TMacroItem collection item, so Im assuming that my code for the TObjectHierarcy is incorrect.


NOTE: For this to work, U need 2 buttons on the form, Link buttons onclick events to the repective onclick procedures in the code.

(************************)
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;
(********************************************************************)
type
  TObjectItem = class(TCollectionItem)
    private
      FName:String;
    public
      procedure Assign(Source: TPersistent); override;
    published
      property Name: String Read FName Write FName;
  end;
  TObjectHierarcy = class(TCollection)
    private
      FOwner : TComponent;
    protected
      function GetOwner : TPersistent; override;
      function GetItem(Index: Integer): TObjectItem;
      procedure SetItem(Index: Integer; Value: TObjectItem);
    public
      constructor Create(AOwner : TComponent);
      destructor Destroy;
      function Add:TObjectItem;

      property Items[Index:integer]:TObjectItem Read GetItem Write SetItem;
    published

  end;
(*******************************)
  TMacroItem = class(TCollectionItem)
    private
      FMacroName:string;
      FWindow:TObjectHierarcy;
    public
    procedure Assign(Source: TPersistent); override;
    published
      property MacroName: String read FMacroName write FMacroName;
      Property ObjectContainer : TObjectHierarcy Read FObjectContainer write FObjectContainer;
  end;
  TMacroList = class(TCollection)
  private
    FOwner:TComponent;
  protected
      function GetOwner : TPersistent; override;
      function GetItem(Index: Integer): TMacroItem;
      procedure SetItem(Index: Integer; Value: TMacroItem);
    public
      constructor Create(AOwner : TComponent);
      destructor Destroy;
      function Add:TMacroItem;

      property Items[Index:integer]:TMacroItem Read GetItem Write SetItem;
    published

  end;

(*******************************)
  TComp = class(TComponent)
    private
      FMyList:TMacroList;
    public
       constructor Create(AOwner: TComponent);
       Procedure Free;
       destructor Destroy;
    published
      Property MyList : TMacroList Read FMyList write FMyList;
  end;
(*******************************)

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
implementation

{$R *.DFM}
(************************************************************)
(* This is the component that contains the collections *)
constructor TComp.Create(AOwner: TComponent);
Begin
  inherited Create(AOwner);
  Self.FMyList:=TMacroList.Create(Self);
End;
Procedure TComp.Free;
Begin
  Self.FMyList.Clear;
  inherited;
End;
destructor TComp.Destroy;
begin
  inherited Destroy;
End;
(************************************************************)
function TMacroList.GetOwner: TPersistent;
begin
  Result := FOwner;
end;
function TMacroList.GetItem(Index: Integer): TMacroItem;
Begin
  Result:=TMacroItem(inherited GetItem(Index));
End;
procedure TMacroList.SetItem(Index: Integer; Value: TMacroItem);
Begin
  inherited SetItem(Index,Value);
End;
constructor TMacroList.Create(AOwner: TComponent);
begin
  inherited Create(TMacroItem);
  FOwner := AOwner;
end;
destructor TMacroList.Destroy;
Begin
  Self.Clear;
  inherited destroy;
End;
function TMacroList.Add:TMacroItem;
Begin
  Result:=TMacroItem(inherited Add);
  Result.FObjectContainer:=TObjectHierarcy.Create(Self.FOwner);
End;
(************************************************************)
procedure TMacroItem.Assign(Source: TPersistent);
begin
  if Source is TMacroItem then
  Begin
    MacroName:= TMacroItem(Source).MacroName;
    Self.ObjectContainer.Assign(TMacroItem(Source).ObjectContainer); // Is this right ???
  End
  else
    inherited; //raises an exception
end;
(************************************************************)
constructor TObjectHierarcy.Create(AOwner: TComponent);
begin
  inherited Create(TObjectItem);
  FOwner := AOwner;
end;
destructor TObjectHierarcy.Destroy;
Begin
  Self.Clear;
  inherited destroy;
End;
function TObjectHierarcy.GetOwner: TPersistent;
begin
  Result := FOwner;
end;
function TObjectHierarcy.GetItem(Index: Integer): TObjectItem;
Begin
  Result:=TObjectItem(inherited GetItem(Index));
End;
procedure TObjectHierarcy.SetItem(Index: Integer; Value: TObjectItem);
Begin
  inherited SetItem(Index,Value);
End;
function TObjectHierarcy.Add:TObjectItem;
Begin
  Result:=TObjectItem(inherited Add);
End;
(*********************************)
procedure TObjectItem.Assign(Source: TPersistent);
begin
  if Source is TObjectItem then
  Begin
    Name := TObjectItem(Source).Name;
  End
  else
    inherited; //raises an exception
end;

(******************************)
procedure TForm1.Button1Click(Sender: TObject);
var f:TStream;
   M:TMacroItem;
   O:TObjectItem;
   j:integer;
   Comp:TComp;
begin
  Comp:=tComp.Create(nil);
  M:=Comp.MyList.Add;
    M.MacroName:='Testing 1';
    O:=M.ObjectContainer.Add;
  M:=Comp.MyList.Add;
    M.MacroName:='Testing 2';

  f:=TFileStream.Create('c:\file.txt',fmCreate);
  f.WriteComponent(Comp);
  f.free;
  showmessage('File "c:\file.txt" created'.);

end;

procedure TForm1.Button2Click(Sender: TObject);
var f:Tstream;
    C:TComp;
    M:TMacroItem;
    O:TObjectItem;
    j:Integer;
begin
  C:=TComp.create(nil);
  C.MyList.Clear;
  showmessage(inttostr(C.MyList.count));
  f:=TFileStream.Create('c:\file.txt',fmOpenRead);
  f.ReadComponent(c); // Error occurs here !!!
  For j := 0 to C.MyList.Count-1 do
     ShowMessage(C.MyList.Items[j].MacroName);
  showmessage(inttostr(C.MyList.count));
  f.free;
end;

end.

0
Comment
Question by:CyberKnight
  • 8
  • 7
15 Comments
 
LVL 9

Expert Comment

by:ITugay
ID: 6950001
Hi CyberKnight,

you call inherited for TCollectionItem.Assign, it doesn't overrided in TCollectionItem,
but take a look at implementation of TPersistent.Assign:

...........
procedure TPersistent.AssignTo(Dest: TPersistent);
begin
  Dest.AssignError(Self);
end;

procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;
...........


You can see that it produced error every time you call it, right?
Do not call Inherited assign.

------
Igor.
0
 

Author Comment

by:CyberKnight
ID: 6950088
Hi Igor, so what you are saying is that I shouldnt call the inherited Assign in my assign method.

Ok, Ive tried this and is still doesnt seem to work, I still get an error when I try to read it from the file ?

Can U maybe correct the code for me ?

By the way.... I found a syntax error in the code that I posted, sorry....
(*This is the correct TMacroItem*)

TMacroItem = class(TCollectionItem)
   private
     FMacroName:string;
//     FWindow:TObjectHierarcy; // this line is needs to be removed.
     FObjectContainer:TObjectHierarcy;

   public
   procedure Assign(Source: TPersistent); override;
   published
     property MacroName: String read FMacroName write FMacroName;
     Property ObjectContainer : TObjectHierarcy Read FObjectContainer write FObjectContainer;
 end;
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6950098
>> Hi Igor, so what you are saying is that I shouldnt call the inherited Assign in my assign method.

because it will raise an exception every time is called. TPersistent.Assign declared similar to "abstract" way, and it should be called when you want to inform that tehere is wrong assignment.


>> Can U maybe correct the code for me ?
OK, I will try. Just a moment.

----
Igor.

0
 
LVL 9

Expert Comment

by:ITugay
ID: 6950134
Exploring your code I found a few strange things:

1. Detructor not overrided.
2. Constructor not overrided, but hided with your own. Collection must know what classes is in it.

while I'll continue exploring, can you explain me what is the goal of your task? It seems that model can be reconsidered.

-------
Igor.
0
 
LVL 9

Accepted Solution

by:
ITugay earned 100 total points
ID: 6950227
OK,
here is a "pure" working code.
You can use it as base to continue:

----
Igor


unit Unit2;

interface

uses
  Classes;

type
  TObjectItem = class(TCollectionItem)
  private
    FName: String;
  published
    property Name: String read FName write FName;
  end;

  TObjectHierarcy = class(TOwnedCollection)
  end;

  TMacroItem = class(TCollectionItem)
  private
    FMacroName: String;
    FObjectContainer: TObjectHierarcy;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property MacroName: String read FMacroName write FMacroName;
    property ObjectContainer: TObjectHierarcy read FObjectContainer write FObjectContainer;
  end;

  TMacroList = class(TOwnedCollection)
  end;

  TComp = class(TComponent)
  private
    FMacroList: TMacroList;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property MacroList: TMacroList read FMacroList write FMacroList;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TComp]);
end;

constructor TMacroItem.Create(Collection: TCollection);
begin
  Inherited;
  FObjectContainer := TObjectHierarcy.Create(Self, TObjectItem);
end;

destructor TMacroItem.Destroy;
begin
  FObjectContainer.Free;
  Inherited;
end;


constructor TComp.Create(AOwner: TComponent);
begin
  Inherited;
  FMacroList := TMacroList.Create(Self, TMacroItem);
end;

destructor TComp.Destroy;
begin
  FMacroList.Free;
  Inherited;
end;

end.
0
 

Author Comment

by:CyberKnight
ID: 6950297
Ok, Thank you Igor !!! I will look at your code.

Maybe my model can be reconsidered....???
It all started when I needed to write the following variable to a file. (Look at the variable "MacroList" below).

Someone suggested that in order to write a variable of that type to a file, I would need to use collections, and Read/writeComponent methods, so that is what Im trying to do.... Can you think of a better solution..??

If you can help, I dont mind increasing the points....really ! :-)

(*****************)
Type
ObjectItem = Record
   Name: String;
   Somedata:Integer;
end;

ObjectH = Record
  ObjectInfo : Array of ObjectItem;
End;

Macro=Record
  MacroName: String;
  MacroObject: ObjectH;
End;
Var MacroList: array of Macro;
(***************)

0
 
LVL 9

Expert Comment

by:ITugay
ID: 6950306
Seems my code exactly what you need. Without any additional points :-)

-------
Igor.

0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:CyberKnight
ID: 6950477
Thanks Igor, I will try it out. If I have any further questions I will post them here....

CK.
0
 

Author Comment

by:CyberKnight
ID: 6951179
Hi Igor...

I need a little assistance please,
Using your code, how do I add a value to the
1. Name property of TObjectItem Object.
2. MacroName property of TObjectHieraracy Object.

Thank you....
CK.

(**************)
procedure TForm1.Button1Click(Sender: TObject);
Var X:tComp;
    F:TStream;
begin
  X:=TComp.Create(Form1);
// (X.MacroList.Add). ; ??? How do I add a value to the name property of the TObjectItem.
// Also how do I add a value to the MacroName property of the TObjectHierarcy


  f:=TFileStream.Create('c:\file.txt',fmCreate);
  f.WriteComponent(Comp1);
  f.free;

  X.Free;

end;
0
 

Author Comment

by:CyberKnight
ID: 6951186
Oh, sorry 4th last line should read
   f.WriteComponent(X);
instead of
   f.WriteComponent(Comp1);
0
 

Author Comment

by:CyberKnight
ID: 6951223
Oh, sorry 4th last line should read
   f.WriteComponent(X);
instead of
   f.WriteComponent(Comp1);
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6952544
hi CK,

here is a sample:

// Comp1 - TComp placed on Form1.

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  S: TFileStream;
  MI: TMacroItem;
  OI: TObjectItem;
begin
  // add first macro item
  MI := TMacroItem(Comp1.MacroList.Add);
  MI.MacroName := 'Macro1';

  // add second macro item
  MI := TMacroItem(Comp1.MacroList.Add);
  MI.MacroName := 'Macro1';

  // add object item into second macro item
  OI := TObjectItem(MI.ObjectContainer.Add);
  OI.Name := 'ObjectItem1';

  S := TFileStream.Create('C:\COMP.DAT', fmCreate);
  S.WriteComponent(Comp1);
  S.Free;
end;

------
Igor.
0
 

Author Comment

by:CyberKnight
ID: 6952727
Hi !
Igor, thanks for all your help,that was great ! I have got it to write and read the data structure to and from a file.

BTW, those DB components on your site are amazing !

Thanx again..

CK
0
 

Author Comment

by:CyberKnight
ID: 6952728
Great, thank you !
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6952784
thanx :-)
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

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…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

744 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

9 Experts available now in Live!

Get 1:1 Help Now