6. 讀取部件的方法的實(shí)現(xiàn)
Reader對(duì)象中用于讀取部件的方法有ReadSignature、ReadPrefix、ReadComponent、ReadRootComponent和ReadComponents。
ReadSignature方法主要用于讀取Delphi Filer對(duì)象標(biāo)簽一般在讀取部件前,都要用調(diào)用ReadSignature方法以指導(dǎo)部件讀寫過程。
procedure TReader.ReadSignature;
var
Signature: Longint;
begin
Read(Signature, SizeOf(Signature));
if Signature <> Longint(FilerSignature) then ReadError(SInvalidImage);
end;
FilerSignature就是Filer對(duì)象標(biāo)簽其值為“TPF0” ,如果讀的不是“TPF0” ,則會(huì)觸發(fā)SInValidImage異常事件。
ReadPrefix方法是用于讀取流中部件前的標(biāo)志位,該標(biāo)志表示該部件是否處于從祖先窗體中繼承的窗體中和它在窗體中的位置是否很重要。
procedure TReader.ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer);
var
Prefix: Byte;
begin
Flags := [];
if Byte(NextValue) and $F0 = $F0 then
begin
Prefix := Byte(ReadValue);
Byte(Flags) := Prefix and $0F;
if ffChildPos in Flags then AChildPos := ReadInteger;
end;
end;
TFilerFlags的定義是這樣的:
TFilerFlag = (ffInherited, ffChildPos);
TFilerFlags = Set of TFilerFlag;
充當(dāng)標(biāo)志的字節(jié)的高四位是$F,低四位是集合的值,也是標(biāo)志位的真正含義。如果ffChildPos置位,則緊接著的整型數(shù)字中放著部件在窗體中的位置序值。
ReadComponent方法用于從Reader對(duì)象的流中讀取部件。Component 參數(shù)指定了要從流中讀取的對(duì)象。函數(shù)返回所讀的部件。
function TReader.ReadComponent(Component: TComponent): TComponent;
var
CompClass, CompName: string;
Flags: TFilerFlags;
Position: Integer;
…
begin
ReadPrefix(Flags, Position);
CompClass := ReadStr;
CompName := ReadStr;
Result := Component;
if Result = nil then
if ffInherited in Flags then
FindExistingComponent else
CreateComponent;
if Result <> nil then
try
Include(Result.FComponentState, csLoading);
if not (ffInherited in Flags) then SetCompName;
if Result = nil then Exit;
Include(Result.FComponentState, csReading);
Result.ReadState(Self);
Exclude(Result.FComponentState, csReading);
if ffChildPos in Flags then Parent.SetChildOrder(Result, Position);
FLoaded.Add(Result);
except
if ComponentCreated then Result.Free;
raise;
end;
end;
ReadCompontent方法首先調(diào)用ReadPrefix方法,讀出部件標(biāo)志位和它的創(chuàng)建次序值(Create Order)。然后用ReadStr方法分別讀出部件類名和部件名。如果Component參數(shù)為nil,則執(zhí)行兩個(gè)任務(wù):
● 如果ffInberited 置位則從Root 找已有部件,否則,就從系統(tǒng)的Class表中找到該部件類型的定義并創(chuàng)建
● 如果結(jié)果不為空,將用部件的ReadState方法讀入各種屬性值,并設(shè)置部件的Parent 屬性,并恢復(fù)它在Parent部件的創(chuàng)建次序。
ReadComponent方法主要是調(diào)用ReadComponent方法從Reader對(duì)象的流中讀取一連串相關(guān)聯(lián)的部件,并分解相互引用關(guān)系。
procedure TReader.ReadComponents(AOwner, AParent: TComponent;
Proc: TReadComponentsProc);
var
Component: TComponent;
begin
Root := AOwner;
Owner := AOwner;
Parent := AParent;
BeginReferences;
try
while not EndOfList do
begin
ReadSignature;
Component := ReadComponent(nil);
Proc(Component);
end;
FixupReferences;
finally
EndReferences;
end;
end;
ReadComponents首先用AOwner和AParent參數(shù)給Root,Owner和Parent賦值,用于重建各部件的相互引用。然后用一個(gè)While循環(huán)讀取部件并用由Proc傳入的方法進(jìn)行處理。在重建引用關(guān)系時(shí),用了BeginReferences、FixUpReferences和EndReferences嵌套模式。
ReadRootComponent方法從Reader對(duì)象的流中將部件及其擁有的部件全部讀出。如果Component參數(shù)為nil,則創(chuàng)建一個(gè)相同類型的部件,最后返回該部件:
function TReader.ReadRootComponent(Root: TComponent): TComponent;
function FindUniqueName(const Name: string): string;
begin
…
end;
var
I: Integer;
Flags: TFilerFlags;
begin
ReadSignature;
Result := nil;
try
ReadPrefix(Flags, I);
if Root = nil then
begin
Result := TComponentClass(FindClass(ReadStr)).Create(nil);
Result.Name := ReadStr;
end else
begin
Result := Root;
ReadStr; { Ignore class name }
if csDesigning in Result.ComponentState then
ReadStr else
Result.Name := FindUniqueName(ReadStr);
end;
FRoot := Result;
if GlobalLoaded <> nil then
FLoaded := GlobalLoaded else
FLoaded := TList.Create;
try
FLoaded.Add(FRoot);
FOwner := FRoot;
Include(FRoot.FComponentState, csLoading);
Include(FRoot.FComponentState, csReading);
FRoot.ReadState(Self);
Exclude(FRoot.FComponentState, csReading);
if GlobalLoaded = nil then
for I := 0 to FLoaded.Count - 1 do TComponent(FLoaded[I]).Loaded;
finally
if GlobalLoaded = nil then FLoaded.Free;
FLoaded := nil;
end;
GlobalFixupReferences;
except
RemoveFixupReferences(Root, '');
if Root = nil then Result.Free;
raise;
end;
end;
ReadRootComponent首先調(diào)用ReadSignature讀取Filer對(duì)象標(biāo)簽。然后在try…except循環(huán)中執(zhí)行讀取任務(wù)。如果Root參數(shù)為nil,則用ReadStr讀出的類名創(chuàng)建新部件,并以流中讀出部件的Name屬性;否則,忽略類名,并判斷Name屬性的性。最后用Root的ReadState方法讀取屬性和其擁有的擁有并處理引用關(guān)系。
Reader對(duì)象中用于讀取部件的方法有ReadSignature、ReadPrefix、ReadComponent、ReadRootComponent和ReadComponents。
ReadSignature方法主要用于讀取Delphi Filer對(duì)象標(biāo)簽一般在讀取部件前,都要用調(diào)用ReadSignature方法以指導(dǎo)部件讀寫過程。
procedure TReader.ReadSignature;
var
Signature: Longint;
begin
Read(Signature, SizeOf(Signature));
if Signature <> Longint(FilerSignature) then ReadError(SInvalidImage);
end;
FilerSignature就是Filer對(duì)象標(biāo)簽其值為“TPF0” ,如果讀的不是“TPF0” ,則會(huì)觸發(fā)SInValidImage異常事件。
ReadPrefix方法是用于讀取流中部件前的標(biāo)志位,該標(biāo)志表示該部件是否處于從祖先窗體中繼承的窗體中和它在窗體中的位置是否很重要。
procedure TReader.ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer);
var
Prefix: Byte;
begin
Flags := [];
if Byte(NextValue) and $F0 = $F0 then
begin
Prefix := Byte(ReadValue);
Byte(Flags) := Prefix and $0F;
if ffChildPos in Flags then AChildPos := ReadInteger;
end;
end;
TFilerFlags的定義是這樣的:
TFilerFlag = (ffInherited, ffChildPos);
TFilerFlags = Set of TFilerFlag;
充當(dāng)標(biāo)志的字節(jié)的高四位是$F,低四位是集合的值,也是標(biāo)志位的真正含義。如果ffChildPos置位,則緊接著的整型數(shù)字中放著部件在窗體中的位置序值。
ReadComponent方法用于從Reader對(duì)象的流中讀取部件。Component 參數(shù)指定了要從流中讀取的對(duì)象。函數(shù)返回所讀的部件。
function TReader.ReadComponent(Component: TComponent): TComponent;
var
CompClass, CompName: string;
Flags: TFilerFlags;
Position: Integer;
…
begin
ReadPrefix(Flags, Position);
CompClass := ReadStr;
CompName := ReadStr;
Result := Component;
if Result = nil then
if ffInherited in Flags then
FindExistingComponent else
CreateComponent;
if Result <> nil then
try
Include(Result.FComponentState, csLoading);
if not (ffInherited in Flags) then SetCompName;
if Result = nil then Exit;
Include(Result.FComponentState, csReading);
Result.ReadState(Self);
Exclude(Result.FComponentState, csReading);
if ffChildPos in Flags then Parent.SetChildOrder(Result, Position);
FLoaded.Add(Result);
except
if ComponentCreated then Result.Free;
raise;
end;
end;
ReadCompontent方法首先調(diào)用ReadPrefix方法,讀出部件標(biāo)志位和它的創(chuàng)建次序值(Create Order)。然后用ReadStr方法分別讀出部件類名和部件名。如果Component參數(shù)為nil,則執(zhí)行兩個(gè)任務(wù):
● 如果ffInberited 置位則從Root 找已有部件,否則,就從系統(tǒng)的Class表中找到該部件類型的定義并創(chuàng)建
● 如果結(jié)果不為空,將用部件的ReadState方法讀入各種屬性值,并設(shè)置部件的Parent 屬性,并恢復(fù)它在Parent部件的創(chuàng)建次序。
ReadComponent方法主要是調(diào)用ReadComponent方法從Reader對(duì)象的流中讀取一連串相關(guān)聯(lián)的部件,并分解相互引用關(guān)系。
procedure TReader.ReadComponents(AOwner, AParent: TComponent;
Proc: TReadComponentsProc);
var
Component: TComponent;
begin
Root := AOwner;
Owner := AOwner;
Parent := AParent;
BeginReferences;
try
while not EndOfList do
begin
ReadSignature;
Component := ReadComponent(nil);
Proc(Component);
end;
FixupReferences;
finally
EndReferences;
end;
end;
ReadComponents首先用AOwner和AParent參數(shù)給Root,Owner和Parent賦值,用于重建各部件的相互引用。然后用一個(gè)While循環(huán)讀取部件并用由Proc傳入的方法進(jìn)行處理。在重建引用關(guān)系時(shí),用了BeginReferences、FixUpReferences和EndReferences嵌套模式。
ReadRootComponent方法從Reader對(duì)象的流中將部件及其擁有的部件全部讀出。如果Component參數(shù)為nil,則創(chuàng)建一個(gè)相同類型的部件,最后返回該部件:
function TReader.ReadRootComponent(Root: TComponent): TComponent;
function FindUniqueName(const Name: string): string;
begin
…
end;
var
I: Integer;
Flags: TFilerFlags;
begin
ReadSignature;
Result := nil;
try
ReadPrefix(Flags, I);
if Root = nil then
begin
Result := TComponentClass(FindClass(ReadStr)).Create(nil);
Result.Name := ReadStr;
end else
begin
Result := Root;
ReadStr; { Ignore class name }
if csDesigning in Result.ComponentState then
ReadStr else
Result.Name := FindUniqueName(ReadStr);
end;
FRoot := Result;
if GlobalLoaded <> nil then
FLoaded := GlobalLoaded else
FLoaded := TList.Create;
try
FLoaded.Add(FRoot);
FOwner := FRoot;
Include(FRoot.FComponentState, csLoading);
Include(FRoot.FComponentState, csReading);
FRoot.ReadState(Self);
Exclude(FRoot.FComponentState, csReading);
if GlobalLoaded = nil then
for I := 0 to FLoaded.Count - 1 do TComponent(FLoaded[I]).Loaded;
finally
if GlobalLoaded = nil then FLoaded.Free;
FLoaded := nil;
end;
GlobalFixupReferences;
except
RemoveFixupReferences(Root, '');
if Root = nil then Result.Free;
raise;
end;
end;
ReadRootComponent首先調(diào)用ReadSignature讀取Filer對(duì)象標(biāo)簽。然后在try…except循環(huán)中執(zhí)行讀取任務(wù)。如果Root參數(shù)為nil,則用ReadStr讀出的類名創(chuàng)建新部件,并以流中讀出部件的Name屬性;否則,忽略類名,并判斷Name屬性的性。最后用Root的ReadState方法讀取屬性和其擁有的擁有并處理引用關(guān)系。

