首页 / 软件开发 / Delphi / 第二十章-开发Delphi对象式数据管理功能(四)(5)
第二十章-开发Delphi对象式数据管理功能(四)(5)2007-05-076. 读取部件的方法的实现Reader对象中用于读取部件的方法有ReadSignature、ReadPrefix、ReadComponent、ReadRootComponent和ReadComponents。ReadSignature方法主要用于读取Delphi Filer对象标签一般在读取部件前,都要用调用ReadSignature方法以指导部件读写过程。procedure TReader.ReadSignature;varSignature: Longint;beginRead(Signature, SizeOf(Signature));if Signature <> Longint(FilerSignature) then ReadError(SInvalidImage);end;FilerSignature就是Filer对象标签其值为“TPF0” ,如果读的不是“TPF0” ,则会触发SInValidImage异常事件。ReadPrefix方法是用于读取流中部件前的标志位,该标志表示该部件是否处于从祖先窗体中继承的窗体中和它在窗体中的位置是否很重要。procedure TReader.ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer);varPrefix: Byte;beginFlags := [];if Byte(NextValue) and $F0 = $F0 thenbeginPrefix := Byte(ReadValue);Byte(Flags) := Prefix and $0F;if ffChildPos in Flags then AChildPos := ReadInteger;end;end;TFilerFlags的定义是这样的:TFilerFlag = (ffInherited, ffChildPos); TFilerFlags = Set of TFilerFlag; 充当标志的字节的高四位是$F,低四位是集合的值,也是标志位的真正含义。如果ffChildPos置位,则紧接着的整型数字中放着部件在窗体中的位置序值。ReadComponent方法用于从Reader对象的流中读取部件。Component 参数指定了要从流中读取的对象。函数返回所读的部件。function TReader.ReadComponent(Component: TComponent): TComponent;varCompClass, CompName: string;Flags: TFilerFlags;Position: Integer;…beginReadPrefix(Flags, Position);CompClass := ReadStr;CompName := ReadStr;Result := Component;if Result = nil thenif ffInherited in Flags thenFindExistingComponent elseCreateComponent;if Result <> nil thentryInclude(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);exceptif ComponentCreated then Result.Free;raise;end;end;ReadCompontent方法首先调用ReadPrefix方法,读出部件标志位和它的创建次序值(Create Order)。然后用ReadStr方法分别读出部件类名和部件名。如果Component参数为nil,则执行两个任务:● 如果ffInberited 置位则从Root 找已有部件,否则,就从系统的Class表中找到该部件类型的定义并创建● 如果结果不为空,将用部件的ReadState方法读入各种属性值,并设置部件的Parent 属性,并恢复它在Parent部件的创建次序。ReadComponent方法主要是调用ReadComponent方法从Reader对象的流中读取一连串相关联的部件,并分解相互引用关系。procedure TReader.ReadComponents(AOwner, AParent: TComponent;Proc: TReadComponentsProc);varComponent: TComponent;beginRoot := AOwner;Owner := AOwner;Parent := AParent;BeginReferences;trywhile not EndOfList dobeginReadSignature;Component := ReadComponent(nil);Proc(Component);end;FixupReferences;finallyEndReferences;end;end;ReadComponents首先用AOwner和AParent参数给Root,Owner和Parent赋值,用于重建各部件的相互引用。然后用一个While循环读取部件并用由Proc传入的方法进行处理。在重建引用关系时,用了BeginReferences、FixUpReferences和EndReferences嵌套模式。ReadRootComponent方法从Reader对象的流中将部件及其拥有的部件全部读出。如果Component参数为nil,则创建一个相同类型的部件,最后返回该部件:function TReader.ReadRootComponent(Root: TComponent): TComponent;function FindUniqueName(const Name: string): string;begin…end;varI: Integer;Flags: TFilerFlags;beginReadSignature;Result := nil;tryReadPrefix(Flags, I);if Root = nil thenbeginResult := TComponentClass(FindClass(ReadStr)).Create(nil);Result.Name := ReadStr;end elsebeginResult := Root;ReadStr; { Ignore class name }if csDesigning in Result.ComponentState thenReadStr elseResult.Name := FindUniqueName(ReadStr);end;FRoot := Result;if GlobalLoaded <> nil thenFLoaded := GlobalLoaded elseFLoaded := TList.Create;tryFLoaded.Add(FRoot);FOwner := FRoot;Include(FRoot.FComponentState, csLoading);Include(FRoot.FComponentState, csReading);FRoot.ReadState(Self);Exclude(FRoot.FComponentState, csReading);if GlobalLoaded = nil thenfor I := 0 to FLoaded.Count - 1 do TComponent(FLoaded[I]).Loaded;finallyif GlobalLoaded = nil then FLoaded.Free;FLoaded := nil;end;GlobalFixupReferences;exceptRemoveFixupReferences(Root, "");if Root = nil then Result.Free;raise;end;end;ReadRootComponent首先调用ReadSignature读取Filer对象标签。然后在try…except循环中执行读取任务。如果Root参数为nil,则用ReadStr读出的类名创建新部件,并以流中读出部件的Name属性;否则,忽略类名,并判断Name属性的唯一性。最后用Root的ReadState方法读取属性和其拥有的拥有并处理引用关系。