Delphi 我们可以在运行时为表单加载dfm文件吗?

Delphi 我们可以在运行时为表单加载dfm文件吗?,delphi,Delphi,Delphi应用程序是否可以接收包含对象、属性和事件分配的dfm文件,并像处理用它编译的内部dfm一样加载所有这些信息 我们怎么能那样做?有直达的方法吗 注意:应用程序已经有了包含正确类和方法以及事件的代码。我们还可以远程接收某种脚本,该脚本可以由我的应用程序读取,从而创建与dfm文件规范匹配所需的对象。就像Web浏览器解释HTML、css和JS文件一样 向您展示了一个DFM表单设计文件,您想实例化它吗 如果没有附带的PAS源文件,这是不可能的。您需要实现类的行为和交互方式。(如果没有实现,即D

Delphi应用程序是否可以接收包含对象、属性和事件分配的dfm文件,并像处理用它编译的内部dfm一样加载所有这些信息

我们怎么能那样做?有直达的方法吗


注意:应用程序已经有了包含正确类和方法以及事件的代码。我们还可以远程接收某种脚本,该脚本可以由我的应用程序读取,从而创建与dfm文件规范匹配所需的对象。就像Web浏览器解释HTML、css和JS文件一样

向您展示了一个DFM表单设计文件,您想实例化它吗

如果没有附带的PAS源文件,这是不可能的。您需要实现类的行为和交互方式。(如果没有实现,即DFM不引用事件处理程序,那么如果您拥有或解析来自DFM的类名,那么您可以这样做。但是您必须知道或解析表单类的所有已发布成员,从而使此解决方案具有学术性)

即使您有源文件,您也需要在编译时使用它才能创建类

如果在编译时同时拥有设计文件和源文件,那么将它们添加到项目中,就不需要从文件加载表单,因为表单包含在可执行文件的资源中。只需在运行时使用默认构造函数
Create
,即可创建表单

当您有一个用于单个PAS源文件的二级DFM表单文件时,然后使用
CreateNew
构造函数基于相同的代码创建一个替代表单对象(例如,隐藏一些控件或设置其样式)


如果您的DFM文件是在运行时从窗体的特定状态创建的,则可以按正常方式创建窗体,但可以使用的一个答案还原该特定状态。

确实可以在运行时加载.DFM文件并创建该DFM文件表示的窗体

我已经编写了一些代码来实现这一点:

但是:请注意:您需要在registerAccessaryClasses过程中添加更多RegisterClass(TSomeComponent)行。如前所述,例如,如果您尝试加载一个包含TSpeedbutton的.dfm文件,您将得到一个异常:只需将RegisterClass(TSpeedbutton)添加到RegisterAccessaryClasses过程

unit DynaFormF;  // This is a normal Delphi form - just an empty one (No components dropped on the form)

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TfrmDynaForm = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmDynaForm: TfrmDynaForm;

implementation

{$R *.dfm}

end.
//:

unitdynaloaddfmu;
{$O-}
接口
使用
窗口、消息、系统、类、图形、控件、窗体、,
对话框、StdCtrls、ExtCtrls、ComCtrls、utils08、DynaFormF;
变量
DebugSL:t字符串;
过程ShowDynaFormModal(文件名:字符串);
实施
过程注册必需类;
开始
寄存器类(TfrmDynaForm);
注册类(TPanel);
注册类(TMemo);
注册类(TTimer);
寄存器类(TListBox);
寄存器类(TSplitter);
注册类(TEdit);
寄存器类(TCheckBox);
寄存器类(TButton);
注册类(TLabel);
注册类(TRadioGroup);
结束;
类型
TCracketComponent=类(TComponent)
受保护的
程序设计;
结束;
变量
类注册:布尔;
程序移除阀门(SL:T管柱);
常数
键1=‘开’;
键2='=';
变量
i、 k1,k2:整数;
S:字符串;
开始
对于i:=SL.Count-1减至0开始
S:=SL[i];
k1:=位置(键1,S);
k2:=位置(键2,S);
如果(k1 0)和(k2>k1),则开始
//删除它:
SL.删除(i);
结束;
结束;
结束;
过程报告布尔值(S:字符串;B:布尔值);
常数
Txts:String=(
“清除”、“设置”
);
开始
如果已分配(DebugSL),则开始
S:=S+':'+Txts[B];
DebugSL.Add(S);
结束;
结束;
过程集合组件样式(AForm:TForm);
变量
a组件:t组件;
i:整数;
B1,B2:布尔型;
开始
对于i:=0到AForm.ComponentCount-1,开始
a组件:=形式组件[i];
如果组件为TTimer,则开始
//TTIMER:
B1:=组件状态下的CSD设计;
//不起作用:试图使TTimer像在DelphiIDE的窗体设计器中一样可见。
tCrackedComponent(组件)。更新设计;
B2:=组件状态下的CSD设计;
ReportBoolean('设置前:',B1);
ReportBoolean('设置后:',B2);
结束;
结束;
结束;
过程ShowDynaFormModalPrim(文件名:String);
变量
FormDyna:TfrmDynaForm;
S1:TFileStream;
S1m:TMemoryStream;
S2:TMemoryStream;
S:字符串;
k1,k2:整数;
读者:踏步者;
SLHelper:TStringlist;
OK:布尔;
MissingClassName、FormName、FormTypeName:字符串;
开始
FormName:=“frmDynaForm”;
FormTypeName:=“TfrmDynaForm”;
FormDyna:=零;
OK:=假;
S1:=TFileStream.Create(文件名、fmOpenRead或fmShareDenyWrite);
尝试
S1m:=TMemoryStream.Create;
尝试
SLHelper:=TStringlist.Create;
尝试
SLHelper.LoadFromStream(S1);
S:=SLHelper[0];
k1:=位置('',S);
k2:=位置(“:”,S);
如果(k1 0)和(k2>k1),则开始
//匹配:
设定长度(S,k2+1);
S:=“对象”+FormName+:“+FormTypeName;
SLHelper[0]:=S;
结束;
移除安全管理员(SLHelper);
SLHelper.SaveToStream(S1m);
最后
SLHelper.Free;
结束;
S1m.位置:=0;
S2:=TMemoryStream.Create;
尝试
ObjectTextToBinary(S1m,S2);
S2.位置:=0;
Reader:=TReader.Create(S2,4096);
尝试
尝试
FormDyna:=TfrmDynaForm.Create(NIL);
Reader.ReadRootComponent(FormDyna);
OK:=正确;
SetComponentStyles(FormDyna);
除了
在E上:异常确实开始
S:=E.ClassName+“”+E.Message;
如果已分配(DebugSL),则开始
DebugSL.add(
unit DynaLoadDfmU;
{$O-}
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls, utils08, DynaFormF;

var
  DebugSL : TStrings;

procedure ShowDynaFormModal(Filename:String);

implementation

procedure RegisterNecessaryClasses;
begin
  RegisterClass(TfrmDynaForm);
  RegisterClass(TPanel);
  RegisterClass(TMemo);
  RegisterClass(TTimer);
  RegisterClass(TListBox);
  RegisterClass(TSplitter);
  RegisterClass(TEdit);
  RegisterClass(TCheckBox);
  RegisterClass(TButton);
  RegisterClass(TLabel);
  RegisterClass(TRadioGroup);
end;

type
  TCrackedTComponent = class(TComponent)
  protected
    procedure UpdateState_Designing;
  end;

var
  ClassRegistered : Boolean;

procedure RemoveEventHandlers(SL:TStrings);
const
  Key1 = ' On';
  Key2 = ' = ';

var
  i, k1,k2 : Integer;
  S        : String;

begin
  for i := SL.Count-1 downto 0 do begin
    S := SL[i];

    k1 := pos(Key1, S);
    k2 := pos(Key2, S);

    if (k1 <> 0) AND (k2 > k1) then begin
      // remove it:
      SL.Delete(i);
    end;

  end;
end;

procedure ReportBoolean(S:String; B:Boolean);
const
  Txts : Array[Boolean] of String = (
  'Cleared', 'Set'
  );

begin
  if Assigned(DebugSL) then begin
    S := S + ' : ' + Txts[B];
    DebugSL.Add(S);
  end;
end;

procedure SetComponentStyles(AForm:TForm);
var
  AComponent : TComponent;
  i          : Integer;
  B1, B2     : Boolean;

begin
  for i := 0 to AForm.ComponentCount-1 do begin
    AComponent := AForm.Components[i];
    if AComponent is TTimer then begin
      // TTIMER:
      B1 := csDesigning in AComponent.ComponentState;

      // Does not work: an attempt to make the TTimer visible like it is in Delphi IDE's form designer.
      TCrackedTComponent(AComponent).UpdateState_Designing;

      B2 := csDesigning in AComponent.ComponentState;
      ReportBoolean('Before setting it: ', B1);
      ReportBoolean('After  setting it: ', B2);
    end;
  end;
end;

procedure ShowDynaFormModalPrim(Filename:String);
var
  FormDyna : TfrmDynaForm;

  S1       : TFileStream;
  S1m      : TMemoryStream;
  S2       : TMemoryStream;
  S        : String;
  k1, k2   : Integer;
  Reader   : TReader;
  SLHelper : TStringlist;
  OK       : Boolean;

  MissingClassName, FormName, FormTypeName : String;

begin
  FormName     := 'frmDynaForm';
  FormTypeName := 'TfrmDynaForm';

  FormDyna := NIL;
  OK       := False;

  S1 := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  try
    S1m := TMemoryStream.Create;
    try
      SLHelper := TStringlist.Create;
      try
        SLHelper.LoadFromStream(S1);

        S := SLHelper[0];

        k1 := pos(' ', S);
        k2 := pos(': ', S);
        if (k1 <> 0) AND (k2 > k1) then begin
          // match:
          SetLength(S, k2+1);
          S := 'object ' + FormName + ': ' + FormTypeName;
          SLHelper[0] := S;
        end;

        RemoveEventHandlers(SLHelper);
        SLHelper.SaveToStream(S1m);
      finally
        SLHelper.Free;
      end;

      S1m.Position := 0;
      S2 := TMemoryStream.Create;
      try
        ObjectTextToBinary(S1m, S2);
        S2.Position := 0;

        Reader := TReader.Create(S2, 4096);
        try
          try
            FormDyna := TfrmDynaForm.Create(NIL);
            Reader.ReadRootComponent(FormDyna);
            OK       := True;
            SetComponentStyles(FormDyna);
          except
            on E:Exception do begin
              S := E.ClassName + '    ' + E.Message;
              if Assigned(DebugSL) then begin
                DebugSL.add(S);
                if (E.ClassName = 'EClassNotFound') then begin
                  // the class is missing - we need one more "RegisterClass" line in the RegisterNecessaryClasses procedure.
                  MissingClassName := CopyBetween(E.Message, 'Class ', ' not found');
                  S := '    RegisterClass(' + MissingClassName + ');';
                  DebugSL.Add(S);
                end;
              end;
            end;
          end;
        finally
          Reader.Free;
        end;
      finally
        S2.Free;
      end;
    finally
      S1m.Free;
    end;
  finally
    S1.Free;
  end;

  if OK then begin
    try
      FormDyna.Caption := 'Dynamically created form: ' + ' -- ' + FormDyna.Caption;
      FormDyna.ShowModal;

    finally
      FormDyna.Free;
    end;
  end else begin
    // failure:
    S := 'Dynamic loading of form file failed.';
    if Assigned(DebugSL)
      then DebugSL.Add(S)
  end;
end;

procedure ShowDynaFormModal(Filename:String);
begin
  if NOT ClassRegistered then begin
    ClassRegistered := True;
    RegisterNecessaryClasses;
  end;

  ShowDynaFormModalPrim(Filename);
end;

{ TCrackedTComponent }

procedure TCrackedTComponent.UpdateState_Designing;
begin
  SetDesigning(TRUE, FALSE);
end;

end.