1

我在设计时创建了 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;

写着“这是我的问题”的那一行是我需要帮助的地方。我不能以这种方式将 NewForm 作为具有第二种形式的变量重用...

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

4

3 回答 3

8

将 NewForm 变量声明为 TForm:

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

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

干燥

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

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 中的字符串创建 Delphi 表单。

于 2012-12-11T08:13:36.513 回答
3

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

var
  NewForm: TForm;

或者

var
  NewForm: TCustomForm;

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

如果您想让编译器在运行时检查 NewForm 实际上是 TMyForm,请使用“软”强制转换:

(NewForm as TMyForm).MyMethod;

当您绝对确定 NewForm 是 TMyForm 时(就像您刚刚创建它时一样),您还可以使用“硬”强制转换:

TMyForm(NewForm).MyMethod;
于 2012-12-11T08:13:43.577 回答
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;
于 2012-12-11T12:35:14.647 回答