汇编 | Java | C# | Delphi | C/C++ |

DELPHI基础教程 第二十章 开发Delphi对象式数据管理功能(三)

第二十章 开发Delphi对象式数据管理功能(三)

copyright dedecms

20.2.1.1 TFiler对象的属性和方法 

copyright dedecms

  1. Root属性 织梦好,好织梦

  声明:property Root: TComponent;

dedecms.com

Root 属性给Filer对象指出被读写的对象中哪一个对象是根或主要拥有者。RootComponentWriteRootComponent方法在读和写部件及其拥有的部件前先设置Root的值。 dedecms.com

  2. Ancestor属性 织梦好,好织梦

  声明:property Ancestor: TPersistent; copyright dedecms

Ancestor属性用于往继承下来的窗体中写部件,因为当写部件时,Write对象只需要写入与所继承的部件不同的属性,所以在写之前要跟踪每个继承的部件,并且比较它们的属性。

本文来自织梦

  如果Ancestornil,就表示没有相应的继承的部件,Writer对象应当将部件完全写入流。Ancestor一般为nil,只有当调用WriteDescendantWriteDescendantRes时,才给赋值。当编写和覆盖DefineProperties时,必须设置Ancestor的值。 copyright dedecms

  3. IgnoreChildren属性 内容来自dedecms

  声明:property Ignorechildren: Boolean;

dedecms.com

IgnoreChildren属性使一个Writer对象存储部件时可以不存储该部件拥有的部件。如果IgnoreChildren属性为True,则Writer对象存储部件不存它拥有的子部件。否则,Writer对象将所有其拥有的对象写入流。

织梦内容管理系统

  4. Create方法 copyright dedecms

  声明:constructor Create(Stream: TStream; BufSize: Cardinal); 织梦内容管理系统

 Create方法创建一个新的Filer对象,建立它和流Stream的联系;并且给它分配一个缓冲区BufferBuffer的大小由BufSize指定。

dedecms.com

  5. Defineproperty方法 内容来自dedecms

  声明:procedure Defineproperty(const Name: String; ReadData: TReaderProc; 本文来自织梦

WriteData: TWriterProc; HasData: Boolean); virtual; abstract;

本文来自织梦

Defineproperty方法定义Filer对象将作为属性存储的数据。Name参数描述接受的属性名,该属性不在published部分定义。ReadDataWriteData参数指定在存取对象时读和写所需数据的方法。HasData参数在运行时决定了属性是否有数据要存储。 本文来自织梦

  只有当对象有数据要存储时,才在该对象的DefineProperties中调用DefinePropertyDefineProperties有一个Filer对象作为它的参数,调用的就是该Filer对象的DefinePropertyDefineBinaryProperty方法。当定义属性时,Writer对象应当引用Ancestor属性,如果该属性非空,Writer对象应当只写入与从Ancestor继承的不同的属性的值。 内容来自dedecms

  一个最简单的例子是TComponentDefineProperties方法。尽管TComponent 没有在published中定义LeftTop属性,但该方法存储了部件的位置信息。 dedecms.com

 

织梦好,好织梦

procedure TComponent.DefineProperties(Filer: TFiler);

copyright dedecms

begin 织梦内容管理系统

Filer.DefineProperty('Left', ReadLeft, WriteLeft, LongRec(FDesignInfo).Lo <> 0); dedecms.com

Filer.DefineProperty('Top', ReadTop, WriteTop, LongRec(FDesignInfo).Hi <> 0); 织梦内容管理系统

end;

本文来自织梦

  内容来自dedecms

6. DefineBinaryproperty方法 内容来自dedecms

  声明:procedure DefineBinaryproperty(const Name: String;

织梦好,好织梦

ReadData, WriteData: TStreamProc;

本文来自织梦

HisData: Boolean); virtual; abstract; dedecms.com

DefineBinaryProperty方法定义Filer对象作为属性存储的二进制数据。Name参数描述属性名。ReadDataWriteData参数描述所存储的对象中读写所需数据的方法。HasData参数在运行时决定属性是否有数据要存。

dedecms.com

  DefineBinaryPropertyDefineProperty方法的不同之处在于,二进制型的属性直接用Stream对象读写,而不是通过Filer对象。通过ReadDataWriteData传入的方法,直接将对象数据写入流或从流读出。 内容来自dedecms

  DefineBinaryProperty属性用得较少。只有标准的VCL对象定义了象图形、图像之类的二进制属性的部件中才用它。 dedecms.com

  7. FlushBuffer方法

织梦好,好织梦

  声明:procedure FlushBuffer; virtual: abstract;

本文来自织梦

FlushBuffer方法用于使Filer对象的缓冲区与相联的Stream对象同步。对Reader对象来说,是通过重新分配缓冲区;对于Writer对象是通过写入当前缓冲区。 copyright dedecms

  FlushBuffer是一个抽象方法,TReaderTWriter都覆盖了它,提供了具体实现。

copyright dedecms

 

织梦好,好织梦

20.2.1.2 TFiler对象的实现原理 copyright dedecms

 

dedecms.com

  TFiler对象是Filer对象的基础类,它定义的大多数方法都是抽象类型的,没有具体实现它,这些方法要在TReaderTWrite中覆盖。但它们提供了Filer对象的框架,了解它无疑是很重要的。 内容来自dedecms

  1. TFiler对象属性的实现

本文来自织梦

  TFiler对象定义了三个属性:RootAncestorIgnoreChildren。正如定义对象属性通常所采用的方法那样,要在private部分定义存储属性值的数据域,然后在publicPublished部分定义该属性,并按需要增加读写控制。它们的定义如下: 内容来自dedecms

   织梦好,好织梦

TFiler = class(TObject) dedecms.com

private 本文来自织梦

织梦好,好织梦

FRoot: TComponent; copyright dedecms

FAncestor: TPersistent;

本文来自织梦

FIgnoreChildren: Boolean;

内容来自dedecms

public 本文来自织梦

织梦好,好织梦

property Root: TComponent read FRoot write FRoot; 本文来自织梦

property Ancestor: TPersistent read FAncestor write FAncestor; 本文来自织梦

property IgnoreChildren: Boolean read FIgnoreChildren write FIgnoreChildren;

内容来自dedecms

end;

织梦好,好织梦

  内容来自dedecms

  它们在读写控制上都是直接读写私有的数据域。 内容来自dedecms

  在介绍TReaderTWriter的实现,我们还会看到这几个属性的原理介绍。 织梦好,好织梦

  2. TFiler对象方法的实现

织梦内容管理系统

  在TFiler对象定义的众多方法中很多都是抽象类方法,没有具体实现。在TFiler 的后继对象TReader中覆盖了这些方法。在后面章节,会介绍这些方法的实现。 内容来自dedecms

  在TFiler对象中有具体实现的有两个方法CreateDestroy

本文来自织梦

  ⑴ Create方法的实现 织梦内容管理系统

  Create方法是TFiler的构造方法,它有两个参数StreamBufSizeStream是指定与TFiler对象相联系的Stream对象,Filer对象都是用Stream对象完成具体的读写。BufSizeTFiler对象内部开设的缓冲区的大小。Filer对象内部开设缓冲区是为了加快数据的读写,它的实现如下: 织梦好,好织梦

 

本文来自织梦

constructor TFiler.Create(Stream: TStream; BufSize: Integer);

内容来自dedecms

begin 织梦好,好织梦

FStream := Stream; dedecms.com

GetMem(FBuffer, BufSize); 本文来自织梦

FBufSize := BufSize;

copyright dedecms

end; 织梦好,好织梦

  本文来自织梦

  FStreamFBufferFBufSize都是TFilerprivate部分定义的数据域。FStream表示与Filer对象相联的Stream对象,FBuffer指向Filer对象内部开设的缓冲区,FBufSize是内部缓冲区的大小。Create方法用Stream参数值给FStream赋值,然后用GetMem分配BufSize大小的动态内存作为内部缓冲区。

copyright dedecms

  ⑵ Destroy方法的实现

织梦内容管理系统

  Destroy方法是TFiler对象的析构函数,它的作用就是释放动态内存。 copyright dedecms

  copyright dedecms

destructor TFiler.Destroy;

本文来自织梦

begin

copyright dedecms

if FBuffer <> nil then FreeMem(FBuffer, FBufSize);

copyright dedecms

end;

内容来自dedecms

  织梦好,好织梦

20.2.2 TWriter对象

本文来自织梦

  织梦好,好织梦

  TWriter 对象是可实例化的,往流中写数据的Filer对象。TWriter对象直接从TFiler继承而来,除了覆盖从TFiler继承的方法外,还增加了大量的关于写各种数据类型(IntegerStringComponent)的方法。TWriter对象和TReader 对象配合使用将使对象读写发挥巨大作用。 织梦好,好织梦

 

dedecms.com

20.2.2.1 TWriter对象的属性和方法

copyright dedecms

 

本文来自织梦

  1. Position属性 内容来自dedecms

  声明:property Position: Longint; 本文来自织梦

TWriter对象的Position属性表示相关联的流中的当前要写的位置,TReader 对象也有这个属性,但与TReader对象不同的是TWriter对象的Position的值比流的Position值小,这一点一看属性实现就清楚了。

dedecms.com

  2. RootAncesstor属性 本文来自织梦

  声明:property RootAncestor: TComponent;

本文来自织梦

RootAncestor属性表示的是Root属性所指的部件的祖先。如果Root 是继承的窗体,Writer对象将窗体拥有部件与祖先窗体中的相应部件依次比较,然后只写入那些与祖先中的不同的部件。

dedecms.com

  3. Write方法

copyright dedecms

  声明:procedure Write(const Buf; Count: Longint); 内容来自dedecms

Write方法从Buf中往与Writer相关联的流中写入Count个字节。

织梦好,好织梦

  4. WriteListBegin方法 copyright dedecms

  声明:procedure WriteListBegin; 织梦内容管理系统

WriteListBegin方法往Write对象的流中写入项目列表开始标志,该标志意味着后面存储有一连串的项目。Reader对象,在读这一连串项目时先调用ReadListBegin方法读取该标志位,然后用EndOfList判断是否列表结束,并用循环语句读取项目。在调用WriteListBegin方法的后面必须调用WriteListEnd方法写列表结束标志,相应的在Reader对象中有ReadListEnd方法读取该结束标志。 内容来自dedecms

  5. WriteListEnd方法 织梦好,好织梦

  声明:procedure WriteListEnd; dedecms.com

WriteListEnd方法在流中,写入项目列表结束标志,它是与WriteListBegin相匹配的方法。

织梦好,好织梦

  6. WriteBoolean方法 织梦内容管理系统

  声明:procedure WriteBoolean(Value: Boolean);

本文来自织梦

WriteBoolean方法将Value传入的布尔值写入流中。

内容来自dedecms

  7. WriteChar方法 织梦好,好织梦

  声明:procedure WriteChar(Value: char); 本文来自织梦

WriteChar方法将Value中的字符写入流中。

本文来自织梦

  8. WriteFloat方法

织梦内容管理系统

  声明:procedure WriteFloat(Value: Extended);

dedecms.com

WriteFloat方法将Value传入的浮点数写入流中。 本文来自织梦

  9. WriteInteger方法 本文来自织梦

  声明:procedure WriteInteger(Value: Longint);

dedecms.com

WriteInteger方法将Value中的整数写入流中。

本文来自织梦

  10. WriteString方法 织梦内容管理系统

  声明:procedure WriteString(const Value: string); 内容来自dedecms

WriteString方法将Value中的字符串写入流中。

织梦内容管理系统

  11. WriteIdent方法 内容来自dedecms

  声明:procedure WriteIdent(const Ident: string);

dedecms.com

WriteIdent方法将Ident传入的标识符写入流中。

copyright dedecms

  12. WriteSignature方法

copyright dedecms

  声明:procedure WriteSignature;

织梦内容管理系统

WriteSignature方法将Delphi Filer对象标签写入流中。WriteRootComponent方法在将部件写入流之前先调用WriteSignature方法写入Filer标签。Reader对象在读部件之前调用ReadSignature方法读取该标签以指导读操作。 dedecms.com

  13. WritComponent方法 dedecms.com

  声明:procedure WriteComponent(Component: TComponent);

本文来自织梦

WriteComponent方法调用参数ComponentWriteState方法将部件写入流中。在调用WriteState之前,WriteComponent还将ComponentComponetnState属性置为csWriting。当WriteState返回时再清除csWriting.

内容来自dedecms

14. WriteRootComponent方法 织梦内容管理系统

  声明:procedure WriteRootComponent(Root: TComponent); 织梦好,好织梦

WriteRootComponent方法将Writer对象Root属性设为参数Root带的值,然后调用WriteSignature方法往流中写入Filer对象标签,最后调用WriteComponent方法在流中存储Root部件。

copyright dedecms

  dedecms.com

20.2.2.2 TWriter对象的实现

copyright dedecms

  本文来自织梦

  TWriter对象提供了许多往流中写各种类型数据的方法,这对于程序员来说是很重要的功能。TWrite对象往流中写数据是依据不同的数据采取不同的格式的。 因此要掌握TWriter对象的实现和应用方法,必须了解Writer对象存储数据的格式。

内容来自dedecms

  首先要说明的是,每个Filer对象的流中都包含有Filer对象标签。该标签占四个字节其值为“TPF0”。Filer对象为WriteSignatureReadSignature方法存取该标签。该标签主要用于Reader对象读数据(部件等)时,指导读操作。

织梦好,好织梦

  其次,Writer对象在存储数据前都要留一个字节的标志位,以指出后面存放的是什么类型的数据。该字节为TValueType类型的值。TValueType是枚举类型,占一个字节空间,其定义如下:

dedecms.com

 

本文来自织梦

  TValueType = (VaNull, VaList, VaInt8, VaInt16, VaInt32, VaEntended, VaString, VaIdent,

dedecms.com

VaFalse, VaTrue, VaBinary, VaSet, VaLString, VaNil, VaCollection);

copyright dedecms

  copyright dedecms

因此,对Writer对象的每一个写数据方法,在实现上,都要先写标志位再写相应的数据;Reader对象的每一个读数据方法都要先读标志位进行判断,如果符合就读数据,否则产生一个读数据无效的异常事件。VaList标志有着特殊的用途,它是用来标识后面将有一连串类型相同的项目,而标识连续项目结束的标志是VaNull。因此,在Writer对象写连续若干个相同项目时,先用WriteListBegin写入VaList标志,写完数据项目后,再写出VaNull标志;而读这些数据时,以ReadListBegin开始,ReadListEnd结束,中间用EndofList函数判断是否有VaNull标志。

dedecms.com

  下面就介绍它们的实现。

内容来自dedecms

  1. TWriter对象属性的实现

copyright dedecms

  TWriter对象直接从TFiler对象继承,它只增加了PositionRootAncestor属性。 内容来自dedecms

RootAncestor属性在private部分有数据域FRootAncestor存入其值。在属性定义的读与控制上都是直接读取该值。 dedecms.com

  Position属性的定义中包含了两个读写控制方法:GetPositionSetPosition dedecms.com

 

内容来自dedecms

TWriter = class(TFiler)

织梦好,好织梦

private

内容来自dedecms

FRootAncestor: TComponent; dedecms.com

dedecms.com

function GetPosition: Longint;

dedecms.com

procedure SetPosition(Value: Longint);

织梦好,好织梦

public

织梦好,好织梦

织梦内容管理系统

property Position: Longint read GetPosition write SetPosition; copyright dedecms

property RootAncestor: TComponent read FRootAncestor write FRootAncestor; 本文来自织梦

end; 织梦内容管理系统

  内容来自dedecms

GetPositionSetPosition方法实现如下: 织梦好,好织梦

  本文来自织梦

function TWriter.GetPosition: Longint;

本文来自织梦

begin 本文来自织梦

Result := FStream.Position + FBufPos; 内容来自dedecms

end;

内容来自dedecms

 

内容来自dedecms

procedure TWriter.SetPosition(Value: Longint); 本文来自织梦

var 本文来自织梦

StreamPosition: Longint; dedecms.com

begin dedecms.com

StreamPosition := FStream.Position; 内容来自dedecms

{ 只清除越界的缓冲区 } 内容来自dedecms

if (Value < StreamPosition) or (Value > StreamPosition + FBufPos) then

本文来自织梦

begin

内容来自dedecms

WriteBuffer;

织梦好,好织梦

FStream.Position := Value; 本文来自织梦

end

内容来自dedecms

else FBufPos := Value - StreamPosition; copyright dedecms

end; 本文来自织梦

  织梦内容管理系统

  WriteBufferTWriter对象定义的私有方法,它的作用是将Writer 对象内部缓冲区中的有效数据写入流中,并将FBufPos置为0Writer对象的FlushBuffer对象就是用WriteBuffer方法刷新缓冲区。

织梦内容管理系统

  在SetPosition方法中,如果Value值超出了边界(FStream.PositionFStream.Position + FBufPos),就将缓冲区中的内容写入流,重新设置缓冲区在流中的相对位置;否则,就只是移动FBufPos指针。

dedecms.com

  2. TWriter方法的实现

织梦好,好织梦

  ⑴ WriteListBeginWriteListEnd的实现

dedecms.com

  这两个方法都是用于写连续若干个相同类型的值。WriteListBegin写入VaList标志,WriteListEnd写入VaNull标志。

织梦好,好织梦

 

copyright dedecms

procedure TWriter.WriteListBegin; 织梦内容管理系统

begin 织梦内容管理系统

WriteValue(vaList); 内容来自dedecms

end; 织梦内容管理系统

  本文来自织梦

procedure TWriter.WriteListEnd; copyright dedecms

begin

内容来自dedecms

WriteValue(vaNull);

内容来自dedecms

end; 织梦内容管理系统

  内容来自dedecms

  这两个方法都调用TWriter对象的WriteValue方法,该方法主要用于写入TValueType类型的值。

本文来自织梦

  内容来自dedecms

procedure TWriter.WriteValue(Value: TValueType); 本文来自织梦

begin 本文来自织梦

Write(Value, SizeOf(Value)); copyright dedecms

end;

内容来自dedecms

  织梦好,好织梦

  ⑵ 简单数据类型的写入

copyright dedecms

  简单数据类型指的是整型、字符型、字符串型、浮点型、布尔型等。TWriter对象都定义了相应的写入方法。

织梦内容管理系统

  WriteInteger方法用于写入整型数据。

本文来自织梦

  内容来自dedecms

procedure TWriter.WriteInteger(Value: Longint); 织梦内容管理系统

begin 织梦好,好织梦

if (Value >= -128) and (Value <= 127) then copyright dedecms

begin 内容来自dedecms

WriteValue(vaInt8); copyright dedecms

Write(Value, SizeOf(Shortint));

copyright dedecms

end else

dedecms.com

if (Value >= -32768) and (Value <= 32767) then 内容来自dedecms

begin 内容来自dedecms

WriteValue(vaInt16);

copyright dedecms

Write(Value, SizeOf(Smallint));

dedecms.com

end else

织梦好,好织梦

begin

copyright dedecms

WriteValue(vaInt32);

本文来自织梦

Write(Value, SizeOf(Longint)); 内容来自dedecms

end;

织梦内容管理系统

end;

织梦内容管理系统

 

本文来自织梦

  WriteInteger方法将整型数据分为8位、16位和32位三种,并分别用vaInt8vaInt16VaInt32

织梦内容管理系统

  WriteBoolean用于写入布尔型数据: 织梦内容管理系统

  本文来自织梦

procedure TWriter.WriteBoolean(Value: Boolean); 本文来自织梦

begin 本文来自织梦

if Value then

织梦好,好织梦

WriteValue(vaTrue) else

内容来自dedecms

WriteValue(vaFalse); dedecms.com

end;

copyright dedecms

 

织梦内容管理系统

  与其它数据类型不同的是布尔型数据只使用了标志位是存储布尔值,在标志位后没有数据。 织梦好,好织梦

  WriteFloat方法用于写入浮点型数据。 织梦好,好织梦

 

织梦好,好织梦

procedure TWriter.WriteFloat(Value: Extended); dedecms.com

begin 织梦内容管理系统

WriteValue(vaExtended);

本文来自织梦

Write(Value, SizeOf(Extended)); 织梦内容管理系统

end; copyright dedecms

  本文来自织梦

  字符串“True”、“False”和“nil”作为标识符传入是由于Delphi的特殊需要。如果是“True”、“False”和“nil”则写入VaTrueVaFalseVaNil,否则写入VaIdent标志,接着以字符串形式写入标识符。

本文来自织梦

  WriteString方法用于写入字符串 织梦内容管理系统

  

copyright dedecms

procedure TWriter.WriteString(const Value: string);

织梦好,好织梦

var 织梦内容管理系统

L: Integer; dedecms.com

begin

copyright dedecms

L := Length(Value);

本文来自织梦

if L <= 255 then copyright dedecms

begin 织梦好,好织梦

WriteValue(vaString);

dedecms.com

Write(L, SizeOf(Byte)); 织梦好,好织梦

end else 织梦好,好织梦

begin

织梦内容管理系统

WriteValue(vaLString);

本文来自织梦

Write(L, SizeOf(Integer));

织梦内容管理系统

end;

copyright dedecms

Write(Pointer(Value)^, L); 本文来自织梦

end;

内容来自dedecms

  dedecms.com

  Delphi的字符串类型有两种。一种长度小于256个字节,另一种长度小于65536 个字节。WriteString方法区分这两类情况存储字符串,一种设置VaStirng标志,另一种设置VaLString。然后存储字符串的长度值,最后存储字符串数据。 织梦好,好织梦

  WriteChar方法用于写入字符。

dedecms.com

  

内容来自dedecms

procedure TWriter.WriteChar(Value: Char); 织梦内容管理系统

begin

本文来自织梦

WriteString(Value);

copyright dedecms

end; copyright dedecms

 

copyright dedecms

  字符类型的读写是用读写字符串的方法,在读的时候,判断字节数为1时,则为字符型。

内容来自dedecms

  ⑶ 部件的写入

copyright dedecms

  TWriter对象中与写入部件有关的方法有WriteSignatureWritePrefixWriteComponentWriteDescendantWriteRootComponent 本文来自织梦

 WriteSignature方法用于往流中写入Filer对象标签。

织梦内容管理系统

 

dedecms.com

procedure TWriter.WriteSignature;

本文来自织梦

begin copyright dedecms

Write(FilerSignature, SizeOf(FilerSignature));

织梦内容管理系统

end;

织梦好,好织梦

 

copyright dedecms

  FilerStgnature是字符串常量,其值为“TPF0”,代表对象标签。 dedecms.com

  WritePrefix方法用于在写入部件前写入ffInheritedffChildPos标志,这些标志表示部件的继承特征和创建序值特征。

copyright dedecms

 

织梦好,好织梦

procedure TWriter.WritePrefix(Flags: TFilerFlags; AChildPos: Integer); 织梦内容管理系统

var

dedecms.com

Prefix: Byte; 本文来自织梦

begin 本文来自织梦

if Flags <> [] then

内容来自dedecms

begin 内容来自dedecms

Prefix := $F0 or Byte(Flags);

copyright dedecms

Write(Prefix, SizeOf(Prefix)); 织梦好,好织梦

if ffChildPos in Flags then WriteInteger(AChildPos);

本文来自织梦

end;

dedecms.com

end;

copyright dedecms

 

本文来自织梦

  如果ffChildPos置位,则存入部件在Owner中的创建序值。更详细的信息请参阅TReaderReadPrefix方法。

内容来自dedecms

  WriteComponent方法往流中写入部件。

本文来自织梦

  织梦好,好织梦

procedure TWriter.WriteComponent(Component: TComponent); 织梦好,好织梦

  内容来自dedecms

function FindAncestor(const Name: string): TComponent;

织梦内容管理系统

begin

本文来自织梦

织梦内容管理系统

end; 本文来自织梦

 

本文来自织梦

begin 本文来自织梦

Include(Component.FComponentState, csWriting);

织梦好,好织梦

if Assigned(FAncestorList) then 织梦好,好织梦

Ancestor := FindAncestor(Component.Name);

织梦内容管理系统

Component.WriteState(Self);

内容来自dedecms

Exclude(Component.FComponentState, csWriting);

dedecms.com

end;

copyright dedecms

 

copyright dedecms

  方法中用ComponentWritState方法写入部件的属性。在写入之前将Component.FComponentState置为csWriting写入完后再将csWriting复位。 dedecms.com

  WriteDescendant是根据祖先AAncestor的情况写入部件Root 本文来自织梦

 

织梦内容管理系统

procedure TWriter.WriteDescendent(Root: TComponent; AAncestor: TComponent); dedecms.com

begin

本文来自织梦

FRootAncestor := AAncestor; dedecms.com

FAncestor := AAncestor;

本文来自织梦

FRoot := Root; 内容来自dedecms

WriteSignature; 织梦好,好织梦

WriteComponent(Root);

dedecms.com

end; 织梦好,好织梦

  本文来自织梦

方法先调用WriteSignature方法写入Filer对象标签。然后调用WriteComponent将部件Root写入流。

织梦内容管理系统

  WriteRootComponent方法则是调用WriteDescendant方法写入部件,只是将后者的Ancestor参数以nil值传入。  织梦内容管理系统

procedure TWriter.WriteRootComponent(Root: TComponent); copyright dedecms

begin

织梦内容管理系统

WriteDescendent(Root, nil);

dedecms.com

end; dedecms.com

精彩推荐
热点内容
最近更新