调用class种不同形式的函数

Calling class functions of different forms

我有一个应用程序,其中包括 "main" 表格以及其他四种表格(formA、formB、formC、formD)。四种形式中的每一种都有唯一的 class function execute().

现在,在 formD 中,我放置了一个编辑框和一个按钮。在按钮的 OnClick 事件中,根据我在编辑框中传递的表单名称,我想 运行 适当的 class 函数。

我试图通过创建一个 TDictionary 来实现这个任务,我在其中添加了 3 对值,但是没有成功。具体来说,我做了以下事情:

unit FormDU;

interface

type
  TFormD = class(TForm)
  Edit1: TEdit;
  fcShapeBtn1: TfcShapeBtn;
  .............
  .............
public
  class function execute:boolean;
  ..........
  ..........
end;

var
  FormD: TFormD;
  MyList:TDictionary<string,TForm>;


implementation 

class function TFormD.execute:boolean;
  begin
    FormD:= TFormD.Create(nil);
    MyList:= TDictionary<string,TForm>.create;
    MyList.Add('FormA',TFormA);
    MyList.Add('FormB',TFormB);
    MyList.Add('FormC',TFormC);
    FormD.showmodal;
  end;

procedure TFormD.fcShapeBtn1Click(Sender: TObject); 
begin
  // Here I check whether the text in Edit1 box has the value of one of the
  // keys that are included in the MyList dictionary and if yes I want to 
  // trigger the class function execute of the appropriate form...

  if MyList.ContainsKey(Edit1.text) then  // suppose that text= formA
      MyList.Items[Edit1.text].execute // which doesn't work.... 

  // I thought that the 'Items' method of the dictionary would return back 
  // to me the appropriate form type - which is connected to the specific 
  // key - and thus I could call each form's class function execute()
end;

我不知道如何解决这个问题。

你的方法有两个问题:

  1. 你的 TDictionary 被声明为保存 TForm 对象指针,但你的代码试图插入 TForm 派生的 class 类型。那将无法编译。

  2. 您的表单 class 不是从具有 Execute() 方法供它们覆盖的公共基础 class 派生的。因此,您不能只从 TDictionary 中检索一个值并直接调用 Execute。您将不得不求助于使用 RTTI 来查找和调用 Execute()

有一些可能的方法可以解决这个问题:

  1. 从公共基础 class 中导出您的表单 classes,并将该基础 class 的派生词存储在您的 TDictionary 中:

    unit FormBaseU;
    
    interface
    
    uses
      Forms;
    
    type
      TFormBase = class(TForm)
      public
        class function Execute: Boolean; virtual;
      end;
    
      TFormBaseClass = class of TFormBase;
    
    implementation
    
    class function TFormBase.Execute: Boolean;
    begin
      Result := False;
    end;
    
    end.
    

    unit FormDU;
    
    interface
    
    uses
      ..., FormBaseU;
    
    type
      TFormD = class(TFormBase)
        Edit1: TEdit;
        fcShapeBtn1: TfcShapeBtn;
        ...
      public
        class function Execute: Boolean; override;
        ...
      end;
    
    var
      FormD: TFormD;
      MyList: TDictionary<string, TFormBaseClass>;
    
    implementation 
    
    uses
      FormAU, FormBU, FormCU;
    
    class function TFormD.Execute: Boolean;
    begin
      MyList := TDictionary<string, TFormBaseClass>.Create;
    
      // make sure TFormA, TFormB, and TFormC all derive
      // from TFormBase and override Execute() ...
      MyList.Add('FormA', TFormA);
      MyList.Add('FormB', TFormB);
      MyList.Add('FormC', TFormC);
    
      FormD := TFormD.Create(nil);
      FormD.ShowModal;
      FormD.Free;
    end;
    
    procedure TFormD.fcShapeBtn1Click(Sender: TObject); 
    var
      FormClass: TFormBaseClass;
    begin
      if MyList.TryGetValue(Edit1.Text, FormClass) then
        FormClass.Execute;
    end;
    
  2. 做类似的事情,但使用 interface 而不是基础 class(这只适用于对象,而不适用于 class 类型):

    unit MyIntfU;
    
    interface
    
    type
      IMyIntf = interface
        ['{41BEF2B6-C27F-440E-A88B-9E5CF8840034}']
        function Execute: Boolean;
      end;
    
    implementation
    
    end.
    

    unit FormDU;
    
    interface
    
    uses
      ..., MyIntfU;
    
    type
      TFormD = class(TForm, MyIntf)
        Edit1: TEdit;
        fcShapeBtn1: TfcShapeBtn;
        ...
      public
        function Execute: Boolean;
        ...
      end;
    
    var
      FormD: TFormD;
      MyList: TDictionary<string, TForm>;
    
    implementation 
    
    uses
      FormAU, FormBU, FormCU;
    
    function TFormD.Execute: Boolean;
    begin
      MyList := TDictionary<string, TForm>.Create;
    
      // make sure TFormA, TFormB, and TFormC are all
      // instantiated beforehand and implement IMyIntf ...
      MyList.Add('FormA', FormA);
      MyList.Add('FormB', FormB);
      MyList.Add('FormC', FormC);
    
      FormD := TFormD.Create(nil);
      FormD.ShowModal;
      FormD.Free;
    end;
    
    procedure TFormD.fcShapeBtn1Click(Sender: TObject); 
    var
      Form: TForm;
      Intf: IMyIntf;
    begin
      if MyList.TryGetValue(Edit1.Text, Form) then
      begin
        if Supports(Form, IMyIntf, Intf) then
          Intf.Execute;
      end;
    end;
    
  3. 根本不要将 classes/objects 存储在您的 TDictionary 中,而是存储实际的 class 方法:

    unit FormDU;
    
    interface
    
    uses
      ...;
    
    type
      TFormD = class(TForm)
        Edit1: TEdit;
        fcShapeBtn1: TfcShapeBtn;
        ...
      public
        class function Execute: Boolean;
        ...
      end;
    
      TMyClassMethod = function: Boolean of object;
    
    var
      FormD: TFormD;
      MyList: TDictionary<string, TMyClassMethod>;
    
    implementation 
    
    uses
      FormAU, FormBU, FormCU;
    
    class function TFormD.Execute: Boolean;
    begin
      MyList := TDictionary<string, TMyClassMethod>.Create;
    
      MyList.Add('FormA', TFormA.Execute);
      MyList.Add('FormB', TFormB.Execute);
      MyList.Add('FormC', TFormC.Execute);
    
      FormD := TFormD.Create(nil);
      FormD.ShowModal;
      FormD.Free;
    end;
    
    procedure TFormD.fcShapeBtn1Click(Sender: TObject); 
    var
      Meth: TMyClassMethod;
    begin
      if MyList.TryGetValue(Edit1.Text, Meth) then
        Meth;
    end;