|
var list:TStrings; FirstLine:String; iPos : Integer; Form : TForm; begin Result := nil; if FileExists(FileName)=False then ExIT; Form := TForm.Create(Application); list := TStringList.Create; try list.LoadFromFile(FileName); if list.Count=0 then ExIT; FirstLine := list[0]; iPos := Pos(': ',FirstLine); if iPos = 0 then //找不到': ',格式不对 ExIT; list[0]:=Copy(FirstLine,1,iPos)+' TForm'; DeleteErrorLines(list); StringToComponent(list.Text,Form); Result := Form; except Form.Free; Result := nil; end; list.Free; end; 原理就是读入DFM文件后把窗体的类别偷换成Tform。其中还有一个函数: procedure DeleteErrorLines(list:TStrings); var i:Integer; line:String; begin if list.Count=0 then ExIT;
i:=0; while i<list.Count do begin line := Trim(list[i]); if Copy(line,1,2)='On' then list.Delete(i) else Inc(i); end; end; 这个函数是把凡是含有“On”开头的行删除,应为在Delphi中,所有控件的事件都是以“On”开头,删除了这样的行,就能保证StringToComponent(list.Text,Form);不出错,用以上的两个函数就可以写一个DFM窗体察看器了,到目前为止,我还没有搜到哪个人发布了DFM窗体察看器。这样我们就完成了第2个要求。
实际应用中,一个窗体几乎肯定会有事件处理函数,所以我们要达成第1个要求。我这儿提供了两个方案,各有优缺点: 方案一: 程序员在开发时,在窗体的FormCreate(…)中,用LoadTextForm(…)生成窗体文件,然后把窗体上的控件全部移到本窗体上,最后查找窗体上的控件,动态设置事件处理函数。这个方法要求有一套好的控件命名规则,而且开发比较烦琐,享受不到Delphi的IDE所见即所得,自动生成事件关联代码的好处了。不过对Form文件的制作人员限制很小,他们可以直接用Delphi来制作窗体。 方案二: 用这个函数 procedure ReadForm(aFrom : TComponent;aFileName :string=''); var FrmStrings : TStrings; begin RegisterClass(TPersistentClass(aFrom.ClassType)); FrmStrings:=TStringlist.Create ; try if trim(aFileName)='' then FrmStrings.LoadFromFile( gsPathInfo+'\'+aFrom.Name+'.txt') else FrmStrings.LoadFromFile(aFileName); while aFrom.ComponentCount>0 do aFrom.Components[0].Destroy ; aFrom:=StringToComponent(FrmStrings.Text,aFrom) finally FrmStrings.Free; end; UnRegisterClass(TPersistentClass(aFrom.ClassType)); end; 在FormCreate中调用ReadForm(self,…)。 这个方案没有第一个方案的限制,但是要求开发人员必须先完成一个完整的Form文件交给Form文件制作人员, Form文件的制作人员不能修改控件的name,不能添加或删除控件,而且必须保留开发人员给定所有事件处理函数,不能修改函数名。不过很多问题可以写一个Form编辑器来保证不出问题。 具体代码就不写了。 我想,肯定还有跟好的方案来解决动态窗体的问题,希望大家讨论。 (以上代码使用Delphi6编写) 最后,我给出一个我实际项目中的有关动态窗体的函数的UnIT {***************************************** 模块编号:J001DfmFunc 模块名称:Dfm窗体函数集单元 作者:刘爱军 建立日期:2002年12月2日 最后修改日期: 说明:本UnIT包含了一些函数,用于根据Delphi窗体文件格式的文件动态创建窗体 *******************************************}
unIT J001DfmFunc;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, DBCtrls, Grids, DBGrids, Buttons, StdCtrls, ComCtrls,dbcgrids, buttonComps,Tabs,QryGlobal;
type TAllComponentClass = Array of TPersistentClass;
procedure InITClassType(ClassArray:TAllComponentClass);
function ComponentToString(Component: TComponent): string; function StringToComponent(Value: string; Instance:TComponent): TComponent; procedure RegisterAllClasses(aAllCmpClass:TAllComponentClass); procedure UnRegisterAllClasses(aAllCmpClass:TAllComponentClass); function GetObjectString(list:TStrings;BegLine:Integer=0;TypeString:string=''):string; function LoadTextForm(FileName:String):TForm; function LoadTextForm2(FileName:String;out ErrMsg:string):TForm; procedure DeleteErrorLines(list:TStrings); procedure ReadForm(aFrom : TComponent;aFileName :string=''); const RegisteredCompoentClassCount = 32;//数组大小
var AllCmpClass : TAllComponentClass; //存放控件类
implementation
//初始化可以解析的类,可随需要增加 procedure InITClassType(ClassArray:TAllComponentClass); begin SetLength(AllCmpClass,RegisteredCompoentClassCount); AllCmpClass[0] := TForm; AllCmpClass[1] := TGroupBox; AllCmpClass[2] := TPanel; AllCmpClass[3] := TScrollBox; AllCmpClass[4] := TLabel; AllCmpClass[5] := TButton; AllCmpClass[6] := TBITBtn; AllCmpClass[7] := TSpeedButton; AllCmpClass[8] := TStringGrid; AllCmpClass[9] := TImage; AllCmpClass[10] := TBevel; AllCmpClass[11] := TStaticText; AllCmpClass[12] := TTabControl; AllCmpClass[13] := TPageControl; AllCmpClass[14] := TTabSheet; AllCmpClass[15] := TDBNavigator; AllCmpClass[16] := TDBText; AllCmpClass[17] := TDBEdIT; AllCmpClass[18] := TDBMemo; AllCmpClass[19] := TDBGrid; AllCmpClass[20] := TDBCtrlGrid; AllCmpClass[21] := TMemo; AllCmpClass[22] := TSplITter; AllCmpClass[23] := TCheckBox; AllCmpClass[24] := TEdIT; AllCmpClass[25] := TListBox; AllCmpClass[26] := TComboBox; AllCmpClass[27] := TDateTimePicker; AllCmpClass[28] := TImageButton; AllCmpClass[29] := TTabSet; AllCmpClass[30] := TTreeView; AllCmpClass[31] := TListView;
end;
procedure RegisterAllClasses(aAllCmpClass:TAllComponentClass); var i:Integer; begin for i:=0 to RegisteredCompoentClassCount-1 do RegisterClass(aAllCmpClass[i]); end;
procedure UnRegisterAllClasses(aAllCmpClass:TAllComponentClass); var i:Integer; begin for i:=0 to RegisteredCompoentClassCount-1 do UnRegisterClass(aAllCmpClass[i]); end;
function ComponentToString(Component: TComponent): string; var BinStream:TMemoryStream; StrStream: TStringStream; s: string; begin BinStream := TMemoryStream.Create; try StrStream := TStringStream.Create(s); try BinStream.WrITeComponent(Component); BinStream.Seek(0, soFromBeginning); ObjectBinaryToText(BinStream, StrStream); StrStream.Seek(0, soFromBeginning); Result:= StrStream.DataString; finally StrStream.Free;
end; finally BinStream.Free end; end;
function StringToComponent(Value: string; Instance:TComponent): TComponent; var StrStream:TStringStream; BinStream: TMemoryStream; begin StrStream := TStringStream.Create(Value); try BinStream := TMemoryStream.Create; try ObjectTextToBinary(StrStream, BinStream); BinStream.Seek(0, soFromBeginning); Result := BinStream.ReadComponent(Instance);
finally BinStream.Free; end; finally StrStream.Free; end; end;
function GetObjectString(list:TStrings;BegLine:Integer=0;TypeString:string=''):string; 上一页 [1] [2] [3] 下一页 |