使用STRING动态创建表单

时间:2012-12-11 08:09:32

标签: delphi lazarus dynamic-forms

我在设计时创建了5个表单。我需要动态创建每个表单的实例并放在一个选项卡上。

我的问题:如果表单名称在字符串数组中,我会调用我的程序:

ShowForm(FormName[3]);// To show the 3rd form on a tab page.

如何为每个表单定义和创建新实例?

这就是我现在所拥有的:

procedure TForm1.ShowFormOnTab(pProcName:String);
var
  NewForm: TfrmSetupItemCategories;//***HERE IS MY PROBLEM***

  NewTab: TTabSheet;
  FormName: String;

begin
  NewTab := TTabSheet.Create(PageControl1);
  NewTab.PageControl:= PageControl1;
  NewTab.Caption:='hi';
  PageControl1.ActivePage :=  NewTab;

  if pProcName='ProcfrmSetupItemCategories' Then
     begin
       NewForm:=TfrmSetupItemCategories.Create(NewTab);
       NewTab.Caption := NewForm.Caption;
     end;
  if pProcName='ProcfrmZones' Then
     begin
       NewForm:=TfrmZones.Create(NewTab);
       NewTab.Caption := NewForm.Caption;
     end;
.
.
.
end;

HERE IS MY BLBLEM ”这一行是我需要帮助的地方。我不能以这种方式将NewForm重用为具有第二种形式的变量......

注意:我的问题不是标签。而是使用相同的变量名创建表单的新实例。

3 个答案:

答案 0 :(得分:8)

将NewForm变量声明为TForm:

var
  NewForm: TForm;
begin
  NewForm := TMyForm.Create(Tab1); //compiles OK
  NewForm := TMyOtherForm.Create(Tab2); //also compiles OK
end;

我假设TMyForm和TMyOtherForm都是TForm的衍生物。

DRY

您还可以使用class reference变量减少重复代码,如下所示:

procedure TForm1.ShowFormOnTab(pProcName:String);
var
  NewForm: TForm;
  ClassToUse: TFormClass;
  NewTab: TTabSheet;
  FormName: String;

begin
  NewTab := TTabSheet.Create(PageControl1);
  NewTab.PageControl:= PageControl1;
  NewTab.Caption:='hi';
  PageControl1.ActivePage :=  NewTab;

  if pProcName='ProcfrmSetupItemCategories' then
    ClassToUse := TfrmSetupItemCategories
  else if pProcName='ProcfrmZones' then
    ClassToUse := TfrmZones
  else
    ClassToUse := nil;
  if Assigned(ClassToUse) then
  begin
    NewForm := ClassTouse.Create(NewTab);
    NewTab.Caption := NewForm.Caption;
    //if you access custom properties or methods, this is the way:
    if NewForm is TfrmZones then
      TfrmZones(NewForm).ZoneInfo := 'MyInfo';
  end;
end;

注册您的课程,然后从字符串

创建表单

正如Rufo爵士在评论中指出的那样,你甚至可以进一步注册你的课程(我不确定这是否可以在Lazarus中完成,这项练习取决于你)。

首先,在调用ShowFormOnTab方法之前,从类名注册要实例化的表单类,例如:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  RegisterClass(TfrmSetupItemCategories);
  RegisterClass(TfrmZones);
  //and other classes
end;

然后,您可以更改代码以从类名字符串中获取类引用:

procedure TForm1.ShowFormOnTab(pProcName:String);
var
  NewForm: TForm;
  ClassToUse: TFormClass;
  ClassNameToUse: string;
  NewTab: TTabSheet;
  FormName: String;

begin
  NewTab := TTabSheet.Create(PageControl1);
  NewTab.PageControl:= PageControl1;
  NewTab.Caption:='hi';
  PageControl1.ActivePage :=  NewTab;
  //get rid of 'Proc' and add the T
  //or even better, pass directly the class name
  ClassNameToUse := 'T' + Copy(pProcName, 5, MaxInt);
  ClassToUse := TFormClass(FindClass(ClassNameToUse));

  if Assigned(ClassToUse) then
  begin
    NewForm := ClassTouse.Create(NewTab);
    NewTab.Caption := NewForm.Caption;
    //if you access custom properties or methods, this is the way:
    if NewForm is TfrmZones then
      TfrmZones(NewForm).ZoneInfo := 'MyInfo';
  end;
end;

这样,代码对于任意数量的类都保持不变。

有关此内容的更多信息,请查看delphi.about.com中的Creating a Delphi form from a string

答案 1 :(得分:3)

将您的变量声明为祖先类型:

var
  NewForm: TForm;

var
  NewForm: TCustomForm;

缺点:如果要调用自己声明的表单中的任何方法,则需要将变量强制转换为特定的类。

如果您希望编译器在运行时检查NewForm实际上是TMyForm,请使用'soft'强制转换:

(NewForm as TMyForm).MyMethod;

当你完全确定NewForm是TMyForm时(就像刚刚创建它一样),你也可以使用'hard'强制转换:

TMyForm(NewForm).MyMethod;

答案 2 :(得分:0)

对于已注册的类,在使用的表单的初始化中,您可以将其缩短为

Function CreateAndDock(pc:TPageControl;const FormName:String):Boolean;
begin
  Result := false;
  if Assigned(GetClass(FormName)) and GetClass(FormName).InheritsFrom(TCustomForm)   then
  With TFormClass( GetClass(FormName)).Create(pc.Owner) do
    begin
     ManualDock(pc);
     Show;
     Result := true;
    end;
end;

procedure TForm4.Button1Click(Sender: TObject);
begin
   ShowMessage(IntToStr(Integer(CreateAndDock(pagecontrol1,'TDockForm'))));
   ShowMessage(IntToStr(Integer(CreateAndDock(pagecontrol1,'TNotExists'))));
end;