我正在尝试根据用户设置配置编写一个返回两个TForm实例之一的函数:

function TfrmMain.GetCurrentRamEditFrm: TForm;
{ Get the RAM Editor Form instance according to currenttly-set protocol. }
begin
  if frmSetup.GetCurrentProtocol() = FooBus then
    result := RAM_Editor_FooBus.frmRAM_Editor_FooBus
  else
    result := RAM_Editor_SXcp.frmRAM_Editor_SXcp;
end;


我需要此功能,因为此单元(Main.pas)在RAM编辑器表单中读取/写入许多变量。

编译器在以下行跳闸:

GetCurrentRamEditFrm().StatusBar1.Panels[1].Text := get_text(96);

错误消息:Undeclared identifier 'StatusBar1'

如果我明确提供TForm实例,则没有错误:

RAM_Editor_SXcp.frmRAM_Editor_SXcp.StatusBar1.Panels[1].Text := get_text(96);

两种形式的StatusBar声明如下:

type
  TfrmRAM_Editor_SXcp = class(TForm)
    StatusBar1: TStatusBar; // i.e. the scope is "published"
    ...


有趣的是,编译器不介意以下内容:

GetCurrentRamEditFrm().show();

最佳答案

编译器错误是可以理解的,因为TForm没有名为StatusBar1的成员。您以派生形式进行了介绍,我认为这些形式为TfrmRAM_Editor_FooBusTfrmRAM_Editor_SXcp

现在,如果这两种形式是从引入StatusBar1的公共基类派生的,则可以改为返回该公共基类,并且可以编译代码。看起来像这样:

type
  TfrmRAM_Editor_Base = class(TForm)
    StatusBar1: TStatusBar;
    ....
  end;

  TfrmRAM_Editor_FooBus = class(TfrmRAM_Editor_Base)
    ....
  end;

  TfrmRAM_Editor_SXcp = class(TfrmRAM_Editor_Base)
    ....
  end;

function TfrmMain.GetCurrentRamEditFrm: TfrmRAM_Editor_Base;
{ Get the RAM Editor Form instance according to currently-set protocol. }
begin
  if frmSetup.GetCurrentProtocol() = FooBus then
    result := RAM_Editor_FooBus.frmRAM_Editor_FooBus
  else
    result := RAM_Editor_SXcp.frmRAM_Editor_SXcp;
end;


但是,这并不是一个很好的解决方案。我的问题是继承是一个非常严格的机制,并且我不愿意将UI控件公开在表单本身之外使用。意识到Delphi的流机制会强制发布设计时控件,因此可以从外部看到它们,但是在我看来,这是一个糟糕的错误,助长了糟糕的设计。

我个人将定义一个可用于设置状态文本的界面。

type
  ISetStatusText = interface
    [...add GUID here]
    procedure SetStatusText(const Value: string);
  end;


让每个表单都实现此接口,然后可以使用as进行查询。也许更好的方法是让您的GetCurrentRamEditFrm函数返回接口而不是表单。

这避免了您不得不向所有人公开表单的UI实现细节。

关于delphi - 如何编写在运行时返回现有TForm实例的函数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27224439/

10-17 01:29