DELPHI基础教程:开发Delphi对象式数据管理功能(五)[1]

 我来答
舒适还明净的海鸥i
2022-09-29 · TA获得超过1.7万个赞
知道小有建树答主
回答量:380
采纳率:0%
帮助的人:70万
展开全部

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

  

    写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写入流中

   读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 并将读的结果作为函数的返回值

   读取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 <> ;

  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 得到读出的部件

   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: riter;

  procedure WriteIndent;

  const

  Blanks: array[ ] of Char = ;

  var

  I: Integer;

  begin

  for I := to NestingLevel do Writer Write(Blanks SizeOf(Blanks))

  end;

  procedure WriteStr(const S: string)

  begin

  Writer Write(S[ ] Length(S))

  end;

  procedure NewLine;

  begin

  WriteStr(# # )

  WriteIndent;

  end;

  procedure ConvertHeader;

  begin

  …

  end;

  procedure ConvertBinary;

  begin

  …

  end;

  procedure ConvertValue;

  begin

  …

  end;

  procedure ConvertProperty;

  begin

  …

  end;

  procedure ConvertObject;

  begin

  …

  end;

  begin

  NestingLevel := ;

  Reader := TReader Create(Input )

  SaveSeparator := DecimalSeparator;

  DecimalSeparator := ;

  try

  Writer := riter Create(Output )

  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 # # )

  end;

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

  Inherited TestForm : TTestForm[ ]

  或者

  Object TestForm : TTestForm

  前者是ffInherited和ffChildPos置位 后面是都没置位

  ConvertProperty过程用于转化属性

  procedure ConvertProperty;

  begin

  WriteIndent;

  WriteStr(Reader ReadStr)

  WriteStr( = )

  ConvertValue;

  WriteStr(# # )

  end;

  WriteIndent语句写入属性名前的空格 WriteStr(Reader ReadStr)语句写入属性名ConvertValue过程根据属性的类型将属性值转化为字符串 然后写入流中

lishixinzhi/Article/program/Delphi/201311/25088

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式