使用具有相同名称的表单的正确方法

Set*_*Net 2 delphi delphi-10-seattle

我有一个项目有两个具有相同名称的表单.我需要使用其中一个.我假设我可以使用IFDEF来区分它们,但我发现在没有编译器抱怨的情况下我无法将它们都添加到项目中.我的用法子句看起来像这样.

uses
uFileManager, uMount, uSkyMap, uAntenna,
{$IFDEF SDR}
 uSDR,
{$ENDIF}
{$IFDEF R7000Serial}
 uR7000,
{$ENDIF}
uDatabase;

{$R *.dfm}
Run Code Online (Sandbox Code Playgroud)

'uSDR'和'uR7000'单元都有一个名为'Receiver'的表格.当我尝试添加'uR7000'单元时,我得到的项目是:"该项目已包含名为Receiver的表单或模块"

如何将两个单元添加到项目中?

Del*_*ics 5

首先,它不是编译器抱怨而是IDE.

编译器或其他类型的- -如果你有形式并不关心使用相同的名称,只要它们是在不同的单位.VCL的一个着名例子是两个TBitmap类型的存在,一个在Graphics中,另一个在Windows中.如果你需要明确你的意思是什么类型,你只需要在代码中限定类型名称,编译器就会告诉它.

bmpA: Graphics.TBitmap;   // bmpA is a TBitmap as defined in the Graphics unit
bmpB: Windows.TBitmap;    // bmpB is a TBitmap as defined in the Windows unit
Run Code Online (Sandbox Code Playgroud)

没问题.

但是,Delphi 持久性框架确实会关注具有相同名称的持久类,因为持久性框架仅通过其非限定名称来标识类型.

这就是为什么Delphi的每个第三方组件框架都在其类名上使用前缀的原因.这不仅仅是虚荣或时尚.它确保一个库中的组件不会(如Delphi持久性机制)与另一个库中的另一个库混淆(如果两个库都在同一个项目中使用).

底线:坚持使用表单的唯一名称,并根据需要找到其他方法来区分或切换它们.

如果没有关于您的项目的更多详细信息,很难建议如何管理您对哪个特定表单的使用的参考.您可以从公共基类派生,也可以为每个基类定义一个接口.

例如(这只是一个说明性的草图,而不是推荐或完全工作的解决方案):

// Define the interface that your Receiver implementations 
//  must satisfy.  This might include returning a reference to the implementing form.
//
// e.g. in a unit "uiReceiver"

type
  IReceiver = interface
    function Form: TForm;  // returns the form using the common base type, not the specific implementation class
  end;


// in unit uSDR
TfrmSDRReceiver = class(TForm, IReceiver)
  ..implements IReceiver as well as your SDR specific needs
end;

// in unit u7000
TfrmR7000SerialReceiver = class(TForm, IReceiver)
  ..implements IReceiver as well as your R7000 Serial specific needs
end;


// In uReceiver (some unit to "resolve" the receiver)
interface

uses
  uSDR,
  uR7000;

  type
    TReceiver = class
      class function GetReceiver: IReceiver;
    end;

implementation

  class function TReceiver.GetReceiver: IReceiver;
  begin
  {$ifdef SDR}
     result := frmSDRReceiver;
  {$endif}
  {$ifdef R7000} 
     result := frmR7000SerialReceiver;
  {$endif}
  end;

end.
Run Code Online (Sandbox Code Playgroud)

然后,您的应用程序代码使用uReceiver单元(和uiReceiver如果你想指接口类型,例如在一个变量声明)和访问特定的接收器通过所提供的静态类,如实现:

uses
  uReceiver;


implementation

  uses
    uiReceiver;


  ..
  var
    rcvr: IReceiver;
  begin
    rcvr := TReceiver.GetReceiver;

    rcvr.... // work with your receiver through the methods/properties on the interface

    // You can also work with the receiver form, accessing all aspects
    //  common to any TForm via the Form function on the interface (assuming
    //  you chose to provide one):

    rcvr.Form.Show;

    ..
  end;
Run Code Online (Sandbox Code Playgroud)