More collections. Part 1.
In the previous article, we looked at the powerful VCL object - TCollection. Now I want to show you streaming
capabilities of TCollection. And more, we'll create our own VCL component.
Introduction.
Each component property of TPersistent derived class can be saved into .DFM.
I'll use this to save all collection items into the stream and load them from stream.
The example program should read a system registry key and all its values, store key and values name into collection,
and list them to user. The collection can be saved to a file and loaded from it.
WriteComponent and ReadComponent methods.
Function ReadComponent initiates streaming of components and their properties.
It reads data values from the stream and assigns them to Instance's properties. It then constructs a reader object and
calls the reader's ReadRootComponent method to read Instance's property values and construct child objects.
If Instance is nil, ReadComponent constructs a component based on the type information in the stream and returns the
newly constructed component.
Note: Component class should be registered in this case!
Similarly, WriteComponent procedure writes Instance's property values to a stream.
Component and collection classes.
unit ilRegCollection;
interface
uses
Windows, Messages, SysUtils, Classes, registry;
type
TILRegEntry=class;
TILRegEntryList=class;
// collection
TILRegEntryList=class(TOwnedCollection)
private
function GetItem(Index: Integer): TILRegEntry;
procedure SetItem(Index: Integer; const Value: TILRegEntry);
public
Constructor Create(AOwner:TPersistent);
property Items[Index: Integer]: TILRegEntry read GetItem write SetItem; default;
end;
TILRegEntry=class(TCollectionItem)
private
FName:String;
FEntries: TILRegEntryList;
FEntryType: TRegDataType;
FValue: variant;
procedure SetEntries(const Value: TILRegEntryList);
public
procedure Assign(Source:TPersistent);override;
constructor Create(AOwner:TCollection);override;
destructor destroy;override;
published
property EntryName:String read FName write Fname;
property EntryType:TRegDataType read FEntryType write FEntryType;
property value:variant read FValue write Fvalue;
property SubEntries:TILRegEntryList read FEntries write SetEntries;
end;
TILREGSaver = class(TComponent)
private
{ Private declarations }
FRegEntry: TILRegEntryList;
procedure SetRegEntry(const Value: TILRegEntryList);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner:TComponent);override;
destructor destroy;override;
procedure SaveToFile(FileName:string);
procedure LoadFromFile(FileName:string);
procedure SaveToStream(Stream:TStream);
procedure LoadFromStream(Stream:TStream);
published
{ Published declarations }
property RegEntrys:TILRegEntryList read FRegEntry write SetRegEntry;
end;
implementation
{ TILRegEntryList }
constructor TILRegEntryList.Create(AOwner:TPersistent);
begin
Assert(Assigned(AOwner));
inherited Create(AOwner,TILRegEntry);
end;
function TILRegEntryList.GetItem(Index: Integer): TILRegEntry;
begin
Result:=TILRegEntry(inherited GetItem(Index));
end;
procedure TILRegEntryList.SetItem(Index: Integer; const Value: TILRegEntry);
begin
inherited SetItem(index,value);
end;
{ TILRegEntry }
procedure TILRegEntry.Assign(Source: TPersistent);
begin
if Source is TILRegEntry then
with Source as TILRegEntry do
begin
self.FName:=EntryName;
self.FEntryType:=EntryType;
self.SubEntries:=SubEntries;
end
else
inherited Assign(source);
end;
constructor TILRegEntry.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
FEntries:=TILRegEntryList.Create(self);
end;
destructor TILRegEntry.destroy;
begin
inherited;
FEntries.Free;
end;
procedure TILRegEntry.SetEntries(const Value: TILRegEntryList);
begin
FEntries.Assign(Value);
end;
{ TILREGSaver }
constructor TILREGSaver.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FRegEntry:=TILRegEntryList.Create(self);
end;
destructor TILREGSaver.destroy;
begin
FRegEntry.Free;
inherited Destroy;
end;
procedure TILREGSaver.LoadFromFile(FileName: string);
var
fs:TFileStream;
begin
fs:=TFileStream.Create(FileName,fmOpenRead);
try
LoadFromStream(fs);
finally
fs.Free;
end;
end;
procedure TILREGSaver.LoadFromStream(Stream: TStream);
begin
Stream.ReadComponent(self);
end;
procedure TILREGSaver.SaveToFile(FileName: string);
var
fs:TFileStream;
begin
fs:=TFileStream.Create(FileName,fmCreate);
try
saveToStream(fs);
finally
fs.Free;
end;
end;
procedure TILREGSaver.SaveToStream(Stream: TStream);
begin
Stream.WriteComponent(self);
end;
procedure TILREGSaver.SetRegEntry(const Value: TILRegEntryList);
begin
FRegEntry.Assign(Value);
end;
end.
Code explanation.
There are three classes:
1. Collection class (TILRegEntryList) derived from TOwnedCollection.
TILRegEntryList overrides Items property just to avoid type conversation each time when accessing collection item.
2. Collection item (TILRegEntry) class derived from TCollectionItem.
TILRegEntry overrides virtual (!) constructor of TCollectionItem. It's important because collection class should create
TILRegEntry instances instead of TCollectionItem.
Another important method that should be overridden - Assign. Assign method should implement correct assignment of
properties.
EntryName property is a string for Key/Value name.
EntryType property specifies the data type of the data value (e.g. rdString).
Property Value:variant specifies the data value.
Property SubEntries:TILRegEntryList holds collection of the key's subkeys and data values.
The copyright of the article
More collections. Part 1. in
Delphi Programming is owned by Lyapin Ilya. Permission to republish
More collections. Part 1. in print or online must be granted by the author in writing.
Go To Page:
1
2
Articles in this Topic
Discussions in this Topic