看源码理解TStream.WriteComponent

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);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值