TComponent与对象持久

Delphi IDE的流系统用来保证所有TPersistent及其派生类的published的数据都会被自动保存和读取。而TComponent类派生自TPersistent,所有组件都从TComponent派生,因此所有组件都具有自我保存、持久的能力,这是Delphi IDE的流系统所保证的。不过,这样的对象持久系统并不完善,至少,它无法保存对象的非published数据。
Delphi当然会为这种情况提供解决方案,它就是TPersistent声明的DefineProperties()方法,是一个虚方法。在TPersistent的实现中,它是一个空方法。每个TPersistent的派生类需要保存非published数据的时侯,就可以覆盖该方法。
VCL的所有组件被放置在一个Form上之后,它的位置就会被记录下来。保存该 Form,后重新打开,所有放置的组件都还在原来的位置上,包括那些运行时不可见的组件,如Ttimer。这些组件并没有标识位值的“Left”或“Top”属性,那它们的位置信息是如何保存的呢?
可以在一个空白的Form上放置一个TTimer组件,并保存该Form,然后打开该Form的定义文件(如:Form1.dfm),可以看到类似如下的内容:
object Form1: TForm1
Left = 192
Top = 107
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Timer1: TTimer
Left = 160
Top = 64
end
end
寻找到其中的object Timer1: TTimer这一行以及其后的数行:
object Timer1: TTimer
Left = 160
Top = 64
End
这几行记录了TTimer组件,可是很奇怪,TTimer组件本身并没有所谓的“Left”和“Top”属性,为什么在dfm文件的定义中会出现呢?
“Left”和“Top”并非TTimer的published数据,因此它们肯定不是由Delphi IDE的流系统来保存的。
TTimer组件派生自TComponent,而TComponent正是通过重写了TPersistent的DefineProperties()方法来记录下Form上面组件的位置。
来查看一下被Tcomponent覆盖(overriding)了的DefineProperties()方法的代码:
procedure TComponent.DefineProperties(Filer: TFiler);
var
Ancestor: TComponent;
Info: Longint;
begin
Info := 0;
Ancestor := TComponent(Filer.Ancestor);
if Ancestor <> nil then Info := Ancestor.FDesignInfo;
Filer.DefineProperty('Left', ReadLeft, WriteLeft,
LongRec(FDesignInfo).Lo <> LongRec(Info).Lo);
Filer.DefineProperty('Top', ReadTop, WriteTop,
LongRec(FDesignInfo).Hi <> LongRec(Info).Hi);
end;
这几行代码首先检查组件本身是否是从其他类派生的,因为如果存在祖先类而派生类本身没有改变要保存的属性值,该属性值就不必保存了。
然后通过传进的TFiler类的参数Filer来定义要保存的属性的读写方法:
Filer.DefineProperty('Left', ReadLeft, WriteLeft,
LongRec(FDesignInfo).Lo <> LongRec(Info).Lo);
Filer.DefineProperty('Top', ReadTop, WriteTop,
LongRec(FDesignInfo).Hi <> LongRec(Info).Hi);
Filer.DefineProperty()方法的第2、第3个参数分别是读写属性的方法。这两个方法的原型分别如下:
TReaderProc = procedure(Reader: TReader) of object;
TWriterProc = procedure(Writer: TWriter) of object;
TComponent类为保存“Left”和“Top”属性,分别提供了ReadLeft/WriteLeft和ReadTop/WriteTop方法:
procedure TComponent.ReadLeft(Reader: TReader);
begin
LongRec(FDesignInfo).Lo := Reader.ReadInteger;
end;
procedure TComponent.ReadTop(Reader: TReader);
begin
LongRec(FDesignInfo).Hi := Reader.ReadInteger;
end;
procedure TComponent.WriteLeft(Writer: TWriter);
begin
Writer.WriteInteger(LongRec(FDesignInfo).Lo);
end;
procedure TComponent.WriteTop(Writer: TWriter);
begin
Writer.WriteInteger(LongRec(FDesignInfo).Hi);
end;
因此,每个TComponent的实例在被流化到dfm文件时,都会有Left和Top属性,即使组件并没有这两个属性。

0 评论:

发表评论

最近访问者

Google

存档

Labels