Как сохранить значение свойства в поток 2
Автор: Yoav
WEB-сайт: http://www.lmc-mediaagentur.de
The solution above will work, but it forces you to implement streaming support for each of the TStreamableObject objects. Delphi has already implemented this mechanism in for the TPersistent class and the TComponent class, and you can use this mechanism. The class I include here does the job. It holds classes that inherit from TUmbCollectionItem (which in turn inherits from Delphi TCollectionItem), and handles all the streaming of the items. As the items are written with the Delphi mechanism, all published data is streamed.
Notes: This class does not support working within the delphi IDE like TCollection. All objects inheriting from TUmbCollectionItem must be registered using the Classes.RegisterClass function. All objects inheriting from TUmbCollectionItem must implement the assign function. By default, the TUmbCollection owns its items (frees them when the collection is freed), but this functionality can be changed.
unit UmbCollection;
interface
uses
Windows, Messages, SysUtils, Classes, contnrs;
type
TUmbCollectionItemClass = class of TUmbCollectionItem;
TUmbCollectionItem = class(TCollectionItem)
private
FPosition: Integer;
public
{when overriding this method, you must call the inherited assign.}
procedure Assign(Source: TPersistent); override;
published
{the position property is used by the streaming mechanism to place the object in the
right position when reading the items. do not use this property.}
property Position: Integer read FPosition write FPosition;
end;
TUmbCollection = class(TObjectList)
private
procedure SetItems(Index: Integer; Value: TUmbCollectionItem);
function GetItems(Index: Integer): TUmbCollectionItem;
public
function Add(AObject: TUmbCollectionItem): Integer;
function Remove(AObject: TUmbCollectionItem): Integer;
function IndexOf(AObject: TUmbCollectionItem): Integer;
function FindInstanceOf(AClass: TUmbCollectionItemClass; AExact: Boolean =
True;
AStartAt: Integer = 0): Integer;
procedure Insert(Index: Integer; AObject: TUmbCollectionItem);
procedure WriteToStream(AStream: TStream); virtual;
procedure ReadFromStream(AStream: TStream); virtual;
property Items[Index: Integer]: TUmbCollectionItem read GetItems write
SetItems; default;
published
property OwnsObjects;
end;
implementation
{ TUmbCollection }
function ItemsCompare(Item1, Item2: Pointer): Integer;
begin
Result := TUmbCollectionItem(Item1).Position -
TUmbCollectionItem(Item2).Position;
end;
function TUmbCollection.Add(AObject: TUmbCollectionItem): Integer;
begin
Result := inherited Add(AObject);
end;
function TUmbCollection.FindInstanceOf(AClass: TUmbCollectionItemClass;
AExact: Boolean; AStartAt: Integer): Integer;
begin
Result := inherited FindInstanceOf(AClass, AExact, AStartAt);
end;
function TUmbCollection.GetItems(Index: Integer): TUmbCollectionItem;
begin
Result := inherited Items[Index] as TUmbCollectionItem;
end;
function TUmbCollection.IndexOf(AObject: TUmbCollectionItem): Integer;
begin
Result := inherited IndexOf(AObject);
end;
procedure TUmbCollection.Insert(Index: Integer; AObject: TUmbCollectionItem);
begin
inherited Insert(Index, AObject);
end;
procedure TUmbCollection.ReadFromStream(AStream: TStream);
var
Reader: TReader;
Collection: TCollection;
ItemClassName: string;
ItemClass: TUmbCollectionItemClass;
Item: TUmbCollectionItem;
i: Integer;
begin
Clear;
Reader := TReader.Create(AStream, 1024);
try
Reader.ReadListBegin;
while not Reader.EndOfList do
begin
ItemClassName := Reader.ReadString;
ItemClass := TUmbCollectionItemClass(FindClass(ItemClassName));
Collection := TCollection.Create(ItemClass);
try
Reader.ReadValue;
Reader.ReadCollection(Collection);
for i := 0 to Collection.Count - 1 do
begin
item := ItemClass.Create(nil);
item.Assign(Collection.Items[i]);
Add(Item);
end;
finally
Collection.Free;
end;
end;
Sort(ItemsCompare);
Reader.ReadListEnd;
finally
Reader.Free;
end;
end;
function TUmbCollection.Remove(AObject: TUmbCollectionItem): Integer;
begin
Result := inherited Remove(AObject);
end;
procedure TUmbCollection.SetItems(Index: Integer; Value: TUmbCollectionItem);
begin
inherited Items[Index] := Value;
end;
procedure TUmbCollection.WriteToStream(AStream: TStream);
var
Writer: TWriter;
CollectionList: TObjectList;
Collection: TCollection;
ItemClass: TUmbCollectionItemClass;
ObjectWritten: array of Boolean;
i, j: Integer;
begin
Writer := TWriter.Create(AStream, 1024);
CollectionList := TObjectList.Create(True);
try
Writer.WriteListBegin;
{init the flag array and the position property of the TCollectionItem objects.}
SetLength(ObjectWritten, Count);
for i := 0 to Count - 1 do
begin
ObjectWritten[i] := False;
Items[i].Position := i;
end;
{write the TCollectionItem objects. we write first the name of the objects class,
then write all the object of the same class.}
for i := 0 to Count - 1 do
begin
if ObjectWritten[i] then
Continue;
ItemClass := TUmbCollectionItemClass(Items[i].ClassType);
Collection := TCollection.Create(ItemClass);
CollectionList.Add(Collection);
{write the items class name}
Writer.WriteString(Items[i].ClassName);
{insert the items to the collection}
for j := i to Count - 1 do
if ItemClass = Items[j].ClassType then
begin
ObjectWritten[j] := True;
(Collection.Add as ItemClass).Assign(Items[j]);
end;
{write the collection}
Writer.WriteCollection(Collection);
end;
finally
CollectionList.Free;
Writer.WriteListEnd;
Writer.Free;
end;
end;
{ TUmbCollectionItem }
procedure TUmbCollectionItem.Assign(Source: TPersistent);
begin
if Source is TUmbCollectionItem then
Position := (Source as TUmbCollectionItem).Position
else
inherited;
end;
end.
|