【问题标题】:Calling class functions of different forms调用不同形式的类函数
【发布时间】:2018-03-22 17:14:43
【问题描述】:

我有一个应用程序,其中包括“主”表单以及其他四种表单(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;

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

【问题讨论】:

    标签: delphi delphi-10-seattle


    【解决方案1】:

    你的方法有两个问题:

    1. 您的TDictionary 被声明为持有TForm 对象指针,但您的代码正试图插入TForm 派生类类型。那不会编译。

    2. 您的 Form 类不是从一个公共基类派生的,该基类有一个 Execute() 方法供它们覆盖。所以你不能只从TDictionary 中检索一个值并直接调用Execute。您将不得不求助于使用 RTTI 来查找和调用 Execute()

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

    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;
      

    【讨论】:

    • 优秀的答案.. 我一直认为有办法,但找不到。但是我永远不会想到有三种不同的方式来完成这项任务!只是一个简单的说明..正如你提到的第二个解决方案规定了已经实例化的表单,这并不总是很方便......我还想问你:从你的角度来看,你会选择这 3 种方式中的哪一种建议我使用并记住作为基本规则?
    猜你喜欢
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 2020-01-09
    • 1970-01-01
    相关资源
    最近更新 更多