WriteComponent最终调用TWriter.WriteComponent流化控件,根据源码可知,
TWriter.WriteComponent将自身和所拥有的组件(omponent.ComponentCount)写入流中。
注意:组件的Owner 说明了该组件是由谁创建的,这个Component的所有者是谁所有的,谁负责该组件构件的创建和释放。
Delphi的Component都有Owner 属性,是Tcomponet类型(元件)。Owner属性是只读的,并且在运行期是无法修改它的值。
Parent 属性表示这个组件放在那个容器里面。Parent属性可以在运行期被修改。并非所有的Component都有Parent,是TWinctrol类型(窗体控件)Parent属性可以为Nil值。是我们可以利用Controls属性与Components属性去遍历Parent所包含的Child Component和Owner所管理的Child Component()。
TWinControl(obj).ControlCount-----是其所包含的控件有多少个,TWinControl(obj).Controls[i])得其所包含的第i个控件
TComponent(obj).ComponentCount--是其所拥有的控件有多少个,TComponent(obj)..Components[I]的其所管理的第i个控件
TWriter.WriteComponent方法中用Component的WritState方法写入部件的属性。在写入之前将Component.FComponentState置为csWriting写入完后再将csWriting复位
procedure TWriter.WriteComponent(Component: TComponent);
function FindAncestor(const Name: string): TComponent;
var
I: Integer;
begin
for I := 0 to FAncestorList.Count - 1 do
begin
Result := FAncestorList[I];
if SameText(Result.Name, Name) then Exit;
end;
Result := nil;
end;
var
OldAncestor: TPersistent;
OldRootAncestor: TComponent;
AncestorComponent: TComponent;
I: Integer;
begin
OldAncestor := Ancestor;
OldRootAncestor := RootAncestor;
try
Include(Component.FComponentState, csWriting); //在写入之前将Component.FComponentState置为csWriting
for I := 0 to Component.ComponentCount - 1 do
if csSubComponent in Component.Components[I].ComponentStyle then
Include(Component.Components[I].FComponentState, csWriting);
if Assigned(FAncestorList) then
Ancestor := FindAncestor(Component.Name);
if Assigned(FOnFindAncestor) and ((Ancestor = nil) or
(Ancestor is TComponent)) then
begin
AncestorComponent := TComponent(Ancestor);
FOnFindAncestor(Self, Component, Component.Name, AncestorComponent,
FRootAncestor);
Ancestor := AncestorComponent;
end;
Component.WriteState(Self);//Component的WritState方法写入部件的属性
Exclude(Component.FComponentState, csWriting);
for I := 0 to Component.ComponentCount - 1 do
if csSubComponent in Component.Components[I].ComponentStyle then
Exclude(Component.Components[I].FComponentState, csWriting);
finally
Ancestor := OldAncestor;
FRootAncestor := OldRootAncestor;
end;
end;
procedure TWriter.WriteDescendent(Root: TComponent; AAncestor: TComponent);
begin
FRootAncestor := AAncestor;
FAncestor := AAncestor;
FRoot := Root;
WriteSignature;//方法先调用WriteSignature方法写入Filer对象标签
WriteComponent(Root);//调用TWriter.WriteComponent将部件Root写入流
end
procedure TWriter.WriteSignature;
begin
Write(FilerSignature, SizeOf(FilerSignature)); //FilerStgnature是字符串常量,其值为“TPF0”,代表对象标签。
end;
WriteComponent.ReadRootComponent
WriteComponent改过的属性都保存下来,ReadComponent的时候读到TButton它就会动态创建这个对象,然后读取到它的属性,并给属性赋值
ReadComponent方法从当前流中读取由Instance所指定的部件,函数返回所读的部件。
如果Instance为nil,ReadComponent的方法基于流中描述的部件类型信息创建部件,并返回新创建的部件。不为空,不创建新控件。
(实现:ReadComponent:创建了一个Reader对象并调用它的ReadRootComponent方法。 )
ReadRootComponent 先调用 TReader.ReadSignature。ReadSignature 从 stream 中读取 4 字节的内容,如果读出来的内容不是 'TPF0',则触发异常(SInvalidImage)
,表示该 stream 的内容是错误的。然后 ReadRootComponent 调用 ReadPrefix 读取元件的状态信息。
如果 Root 参数是 nil,也就是说 Root 对象还没被创建,则直接从流中读取 Root 的类名,再使用 FindClass 函数找到该类在内存中的地址,并调用该类的构造函数
创建 Root 的实例。
接下来 ReadRootComponent 调用 Root 的 ReadState 虚函数从流中读取 Root 对象的属性。TComponent.ReadState 只有一行代码:Reader.ReadData(Self);。
ReadData 调用 ReadDataInner 读取 root 元件及 root 的子元件的属性信息。
ReadDataInner 先循环调用 ReadProperty 从流中读取 root 元件的属性,直到遇到 EndOfList 标志(vaNull)。ReadProperty 使用 RTTI 函数,将从流中读出的数据
设置为对象的属性。ReadProperty 中还调用了 Instance.DefineProperties,用于实现自定义的属性存储。ReadDataInner 然后循环调用 ReadComponent(nil) 读取子
元件的信息。
1.组件对象的序列化
从TCOMPONENT继承下来的组件对象序列化都简单,因为它本身支持流化,通过流化也就达到了序列化组件对象的目的。
TReader和TWriter都只支持Tcomponent流化,除非你自己写个TReader和TWriter,就有可能支持TPersiten的流化.
function ComponentToString(Component: TComponent): string;
var
BinStream:TMemoryStream;
StrStream: TStringStream;
s: string;
begin
BinStream := TMemoryStream.Create;
try
StrStream := TStringStream.Create(s);
try
BinStream.WriteComponent(Component);
BinStream.Seek(0, soFromBeginning);
ObjectBinaryToText(BinStream, StrStream);
StrStream.Seek(0, soFromBeginning);
Result:= StrStream.DataString;
finally
StrStream.Free;
end;
finally
BinStream.Free
end;
end;
function StringToComponent(Value: string): TComponent;
var
StrStream:TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create(Value);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Seek(0, soFromBeginning);
Result := BinStream.ReadComponent(nil);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
TWriter对象提供了许多往流中写各种类型数据的方法,这对于程序员来说是很重要的功能。TWrite对象往流中写数据是依据不同的数据采取不同的格式的。
TStream和流的关系:创建TWriter 要用流
procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);
var
Writer: TWriter;
begin
Writer := TWriter.Create(Self, 4096);
try
Writer.WriteDescendent(Instance, Ancestor);
finally
Writer.Free;
end;
end;
2.非组件对象的序列化
非组件对象,也就是从TObject或者从Tpersisten继承下来的对象的序列化却要变通一下。
方法很简单,就是sizeof(TMyObject)的大小,定义一个buffer指向对象,直接把那一块内存写入文件,反序列化时从文件读取就可以了,
这就是对非组件对象有效的序列化
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);
var
Writer: TWriter;
begin
Writer := TWriter.Create(Self, 4096);
try
Writer.WriteDescendent(Instance, Ancestor);
finally
Writer.Free;
end;
end;
procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);
var
Writer: TWriter;
begin
Writer := TWriter.Create(Self, 4096);
try
Writer.WriteDescendent(Instance, Ancestor);
finally
Writer.Free;
end;
end;
procedure TStream.WriteComponent(Instance: TComponent);//
begin
WriteDescendent(Instance, nil);
end;
procedure TWriter.WriteDescendent(Root: TComponent; AAncestor: TComponent);
begin
FRootAncestor := AAncestor;
FAncestor := AAncestor;
FRoot := Root;
FLookupRoot := Root;
WriteSignature;
WriteComponent(Root);
end;
//流的写控件方法实现:调用流的写后代方法,传入Ancestor参数是nil
流的写后代方法的实现:调用TWriter的写后代方法
ms.WriteDescendent(obj,nil);
=
ms.WriteComponent(obj);