DELPHI基础教程:开发Delphi对象式数据管理功能(五)[1]
第二十章 开发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
2023-12-06 广告