调用不同形式的类函数

时间:2018-03-22 17:14:43

标签: delphi delphi-10-seattle

我有一个应用程序,其中包括“主”表单以及其他四种表单(formA,formB,formC,formD)。四种表格中的每一种都有一个独特的class function execute()

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

我尝试通过创建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 个答案:

答案 0 :(得分:2)

您的方法存在两个问题:

  1. 您的TDictionary被声明为保存TForm个对象指针,但您的代码正在尝试插入TForm - 派生类类型。那将无法编译。

  2. 您的表单类不是从具有Execute()方法的公共基类派生的。因此,您无法直接从TDictionary检索值并直接致电Execute。您将不得不求助于使用RTTI来查找和调用Execute()

  3. 有一些可行的方法可以解决这个问题:

    1. 从公共基类派生您的Form类,并在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而不是基类(这只适用于对象,而不是类类型):

      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. 根本不在TDictionary中存储类/对象,而是存储实际的类方法:

      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;