首页 考试吧论坛 Exam8视线 考试商城 网络课程 模拟考试 考友录 实用文档 求职招聘 论文下载
2011中考 | 2011高考 | 2012考研 | 考研培训 | 在职研 | 自学考试 | 成人高考 | 法律硕士 | MBA考试
MPA考试 | 中科院
四六级 | 职称英语 | 商务英语 | 公共英语 | 托福 | 雅思 | 专四专八 | 口译笔译 | 博思 | GRE GMAT
新概念英语 | 成人英语三级 | 申硕英语 | 攻硕英语 | 职称日语 | 日语学习 | 法语 | 德语 | 韩语
计算机等级考试 | 软件水平考试 | 职称计算机 | 微软认证 | 思科认证 | Oracle认证 | Linux认证
华为认证 | Java认证
公务员 | 报关员 | 银行从业资格 | 证券从业资格 | 期货从业资格 | 司法考试 | 法律顾问 | 导游资格
报检员 | 教师资格 | 社会工作者 | 外销员 | 国际商务师 | 跟单员 | 单证员 | 物流师 | 价格鉴证师
人力资源 | 管理咨询师考试 | 秘书资格 | 心理咨询师考试 | 出版专业资格 | 广告师职业水平
驾驶员 | 网络编辑
卫生资格 | 执业医师 | 执业药师 | 执业护士
会计从业资格考试会计证) | 经济师 | 会计职称 | 注册会计师 | 审计师 | 注册税务师
注册资产评估师 | 高级会计师 | ACCA | 统计师 | 精算师 | 理财规划师 | 国际内审师
一级建造师 | 二级建造师 | 造价工程师 | 造价员 | 咨询工程师 | 监理工程师 | 安全工程师
质量工程师 | 物业管理师 | 招标师 | 结构工程师 | 建筑师 | 房地产估价师 | 土地估价师 | 岩土师
设备监理师 | 房地产经纪人 | 投资项目管理师 | 土地登记代理人 | 环境影响评价师 | 环保工程师
城市规划师 | 公路监理师 | 公路造价师 | 安全评价师 | 电气工程师 | 注册测绘师 | 注册计量师
缤纷校园 | 实用文档 | 英语学习 | 作文大全 | 求职招聘 | 论文下载 | 访谈 | 游戏
您现在的位置: 考试吧(Exam8.com) > 计算机等级考试 > 计算机二级 > Delphi > 复习资料 > 正文

2011等考Delphi:开发Delphi对象式数据管理功能

来源:考试吧Exam8.com) 2010-10-30 9:21:41 考试吧:中国教育培训第一门户 模拟考场
在本章中将介绍Stream对象和Filer对象的实现原理、应用方法以及在超媒体系统中的应用。这对于运用Delphi 开发高级应用是很重要的。

  ReadComponent方法主要是调用ReadComponent方法从Reader对象的流中读取一连串相关联的部件,并分解相互引用关系。

  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参数给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;

  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首先调用ReadSignature读取Filer对象标签。然后在try…except循环中执行读取任务。如果Root参数为nil,则用ReadStr读出的类名创建新部件,并以流中读出部件的Name属性;否则,忽略类名,并判断Name属性的唯一性。最后用Root的ReadState方法读取属性和其拥有的拥有并处理引用关系。

  7. SetName方法和OnSetName事件

  因为在OnSetName事件中,Name参数是var型的,所以可以用OnSetName事件处理过程修改所读部件的名字。而OnSetName事件处理过程是在SetName方法中实现的。

  procedure TReader.SetName(Component: TComponent; var Name: string);

  begin

  if Assigned(FOnSetName) then FOnSetName(Self, Component, Name);

  Component.Name := Name;

  end;

  SetName方法和OnSetName事件在动态DFM文件的编程中有很重要的作用。

  8. TReader的错误处理

  TReader的错误处理是由Error方法和OnError事件的配合使用完成的。OnError 事件处理过程的Handled参数是var型的布尔变量,通过将Handled设为True或False可影响TReader 的错误处理。OnError事件处理过程是在Error方法中调用的。

  function TReader.Error(const Message: string): Boolean;

  begin

  Result := False;

  if Assigned(FOnError) then FOnError(Self, Message, Result);

  end;

  9. FindMethod和OnFindMethod事件

  有时,在程序运行期间,给部件的方法指针(主要是事件处理过程)动态赋值是很有用的,这样就能动态地改变部件响应事件的方式。在流中读取部件捍做到一点就要利用OnFindMehtod事件。OnFIndMethod事件是在FindMethod方法中被调用的。

  function TReader.FindMethod(Root: TComponent;

  const MethodName: string): Pointer;

  var

  Error: Boolean;

  begin

  Result := Root.MethodAddress(MethodName);

  Error := Result = nil;

  if Assigned(FOnFindMethod) then FOnFindMethod(Self, MethodName, Result,

  Error);

  if Error then PropValueError;

  end;

  OnFindMethod 方法除了可以给部件的MethodName所指定的方法指针动态赋值外,还可修改Error参数来决定是否处理Missing Method错误。方法中调用的MehtodAddress 方法定义在TObject中,它是个很有用的方法,它可以得到对象中定义的public方法的地址。FindMethod方法和OnFindMethod事件在动态DFM的编程中有很重要的作用。

  20.3 Delphi对象式数据管理应用实例

  Delphi 2.0无论是其可视化设计工具,还是可视化部件类库(VCL),都处处渗透了对象存储技术,本节将从Delphi可视化设计内部机制、VCL中的数据存储、BLOB数据操作和动态生成部件的存储几方面介绍对象存储功能的实例应用。

  20.3.1 Delphi 动态DFM文件及部件的存取在超媒体系统中的应用

  Delphi的可视化设计工具是同其部件类库紧密结合在一起的。

  每个部件只有通过一段注册程序并通过Delphi的Install Component功能,才能出现在Component Palette上;部件的属性才有可能出现在Object Inspector窗口中;部件的属性编辑器才能被Delphi环境使用。因为这种浑然天成的关系,DFM文件存取必然得到VCL在程序上的支持。

  DFM文件的部件存取是Delphi可视化设计环境中文件存取的中心问题。因为Delphi可视化设计的核心是窗体的设计。每个窗体对应一个库单元,是应用程序的模块,窗体在磁盘上的存储就是DFM文件。

  DFM文件结构我们前面介绍过了。它实际上是存储窗体及其拥有的所有部件的属性。这种拥有关系是递归的。问题在于如何将这些属性数据与程序中的变量(属性)代码联系起来。

  在Delphi中处理这种联系的过程分为两种情况:设计时和运行时。

  在设计时,建立联系表现为读取DFM 文件,建立DFM文件中的部件及其属性与可视化设计工具(Object Inspector、窗体设计窗口和代码编辑器)的联系,也就是说让这些部件及其属性能出现在这些窗口中,并与代码中的属性定义联系起来;分解联系表现为存储DFM文件,将窗体窗口中的部件及其属性写入DFM文件。

  在运行时,主要是建立联系的过程,即读取DFM文件。这时,DFM文件不是作为独立的磁盘文件,而是以应用程序资源中的RCDATA类型的二进制数据存在。建立联系的过程表现为将资源中的部件及其属性与应用程序中的对象及其数据域联系起来。其过程为:根据DFM中的部件类名创建对象,再将用DFM中的部件属性值给程序中的部件属性赋值。当然要完成这一过程,还必须在代码中有相应的窗体定义,因为方法等代码是不存入部件的。

  VCL对读取DFM文件在代码上的支持是通过Stream对象和Filer对象达到的。在20. 1和20.1节中,我们可以看到Stream对象和Filer对象中有大量的用于存取部件及其属性的方法,尤其在TReader对象中,还有关于错误处理和动态的方法赋值的方法。下面我们就通过程序实例介绍存取DFM文件方法、步骤和注意事项。

  20.3.1.1写DFM文件的过程:WriteComponentResFie

  该过程带有两个参数FileName和Instance。FileName参数指定要写入的DFM文件名,Instance参数是TComponent类型的,它指定要写入的部件名,一般是TForm对象的子类。该过程将Instance部件和其拥有的所有部件写入DFM文件。

  这个过程的意义在于,可以在程序运行过程中产生Delphi的窗体部件和在窗体中插入部件,并由该函数将窗体写入DFM文件,支持了动态DFM文件的重用性。

  该过程的程序是这样的:

  procedure WriteComponentResFile(const FileName: string; Instance: TComponent);

  var

  Stream: TStream;

  begin

  Stream := TFileStream.Create(FileName, fmCreate);

  try

  Stream.WriteComponentRes(Instance.ClassName, Instance);

  finally

  Stream.Free;

  end;

  end;

  函数中,用FileStream创建文件,用Stream对象的WriteComponetRes方法将Instance写入流中。

  20.3.1.2 读DFM文件的函数:ReadComponentResFile

  ReadComponentResFile函数带有两个参数FileName和Instance。FileName参数指定要读DFM文件名,Instance参数指定从DFM文件中要读的部件。该函数从DFM文件中将Instance和它拥有的所有部件,并返回该部件。

  这个函数的意义在于,配合WriteComponentResFile过程的使用支持DFM文件的重用性。

  该函数的程序是这样的:

  function ReadComponentResFile(const FileName: string; Instance: TComponent):

  TComponent;

  var

  Stream: TStream;

  begin

  Stream := TFileStream.Create(FileName, fmOpenRead);

  try

  Result := Stream.ReadComponentRes(Instance);

  finally

  Stream.Free;

  end;

  end;

  程序中使用FileStream对象打开由FileName指定的DFM文件,然后用Stream对象的ReadComponentRes方法读出Instance,并将读的结果作为函数的返回值。

  20.3.1.3 读取Delphi应用程序资源中的部件

  函数InternalReadComponentRes可以读取Delphi应用程序资源中的部件。Delphi 的DFM文件在程序经过编译链接后被嵌入应用程序的资源中,而且格式发生了改变,即少了资源文件头。

  在第一节中曾经介绍过TResourceStream对象,该对象是操作资源媒介上的数据的。函数InternalReadComponentRes用了TResourceStream。程序是这样的:

  function InternalReadComponentRes(const ResName: string;

  var Instance: TComponent): Boolean;

  var

  HRsrc: THandle;

  begin { 避免“EResNotFound”异常事件的出现 }

  HRsrc := FindResource(HInstance, PChar(ResName), RT_RCDATA);

  Result := HRsrc <> 0;

  if not Result then Exit;

  FreeResource(HRsrc);

  with TResourceStream.Create(HInstance, ResName, RT_RCDATA) do

  try

  Instance := ReadComponent(Instance);

  finally

  Free;

  end;

  Result := True;

  end;

  HInstance是一个Delphi VCL定义的全局变量,代表当前应用程序的句柄。函数用了资源访问API函数FindResource来测定是否存在ResName所描述资源。因为在TResourceStream的创建过程还有FindResource等操作,所以函数中调用了FreeResource。最后函数调用了Stream对象的ReadComponent方法读出部件。因为函数的Instance是var类型的参数,所以可以访问Instance,得到读出的部件。

  20.3.1.4 DFM文件与标准文本文件(TXT文件)的相互转换

  在Delphi可视化设计环境中,允许程序员在代码编辑器中以文本的方式浏览和修改DFM文件内容。当用File/Open命令直接打开DFM文件或者选择窗体设计窗口的弹出式菜单上的View as Text命令时,就会在编辑器中出现文本形式的信息。我们姑且将这种文本形式称之为窗体设计脚本。Delphi提供的这种脚本编辑功能是对Delphi可视化设计的一大补充。当然这个脚本编辑能力是有限制的,比方说不能在脚本任意地添加和删除部件,因为代码和DFM脚本是紧密相连的,任意添加和修改会导致不一致性。然而在动态生成的DFM文件中,就不存在这一限制,后面会介绍DFM动态生成技术的应用。

  实际上,DFM文件内容是二进制数据,它的脚本是经过Delphi开发环境自动转化的,而且Delphi VCL中的Classes库单元中提供了在二进制流中的文件DFM和它的脚本之相互转化的过程。它们是ObjectBinaryToText和ObjectTextBinary、ObjectResourceToText和ObjectTextToResource。

  ObjectBinaryToText过程将二进制流中存储的部件转化为基于文本的表现形式,这样就可以用文本处理函数进行处理,还可以用文本编辑器进行查找和替代操作,最后可以将文本再转化成二进制流中的部件。

  ObjectBinaryToText过程的主程序是这样的:

  procedure ObjectBinaryToText(Input, Output: TStream);

  var

  NestingLevel: Integer;

  SaveSeparator: Char;

  Reader: TReader;

  Writer: TWriter;

  procedure WriteIndent;

  const

  Blanks: array[0..1] of Char = ' ';

  var

  I: Integer;

  begin

  for I := 1 to NestingLevel do Writer.Write(Blanks, SizeOf(Blanks));

  end;

  procedure WriteStr(const S: string);

  begin

  Writer.Write(S[1], Length(S));

  end;

  procedure NewLine;

  begin

  WriteStr(#13#10);

  WriteIndent;

  end;

  procedure ConvertHeader;

  begin

  …

  end;

  procedure ConvertBinary;

  begin

  …

  end;

  procedure ConvertValue;

  begin

  …

  end;

  procedure ConvertProperty;

  begin

  …

  end;

  procedure ConvertObject;

  begin

  …

  end;

  begin

  NestingLevel := 0;

  Reader := TReader.Create(Input, 4096);

  SaveSeparator := DecimalSeparator;

  DecimalSeparator := '.';

  try

  Writer := TWriter.Create(Output, 4096);

  try

  Reader.ReadSignature;

  ConvertObject;

  finally

  Writer.Free;

  end;

  finally

  DecimalSeparator := SaveSeparator;

  Reader.Free;

  end;

  end;

  过程中调用的ConvertObject过程是个递归过程,用于将DFM文件中的每一个部件转化为文本形式。因为由于部件的拥有关系,所以部件成嵌套结构,采用递归是最好的方式:

  procedure ConvertObject;

  begin

  ConvertHeader;

  Inc(NestingLevel);

  while not Reader.EndOfList do ConvertProperty;

  Reader.ReadListEnd;

  while not Reader.EndOfList do ConvertObject;

  Reader.ReadListEnd;

  Dec(NestingLevel);

  WriteIndent;

  WriteStr('end'#13#10);

  end;

  NestStingLevel变量表示部件的嵌套层次。WriteIndent是写入每一行起始字符前的空格,ConvertHeader过程是处理部件的继承标志信息。转换成的头信息文本有两种形式。

  Inherited TestForm1: TTestForm[2]

上一页  1 2 3 4 5 6 7 8 9 下一页
  相关推荐:2010年9月计算机等级考试试题及答案解析专题
       预告:名师解析2010年9月计算机等级考试试题答案
       2010年9月计算机等级考试成绩查询时间及入口
       2010年9月计算机等考成绩查询短信免费提醒开通
文章搜索
版权声明:如果计算机等级考试网所转载内容不慎侵犯了您的权益,请与我们联系800@exam8.com,我们将会及时处理。如转载本计算机等级考试网内容,请注明出处。