0

我有一个 TFrame,用于在 Delphi 2010 VCL 项目中搜索实体,在 TFrame 中我有一个按钮编辑,允许用户打开特定表单以浏览该实体。(所有浏览表单都继承自一个通用的基本浏览表单)目前我通过从基本框架继承来实现这一点,然后实现触发特定表单的 Browse 事件。每次唯一的区别是单击事件上显示的形式(类型),有没有一种方法可以用泛型实现这一点。这样我就可以重用相同的基本框架,而不必为每个实体重写相同的代码(有超过 100 个),并且在主机表单的表单创建中传递类型约束以在浏览时打开适当的表单。我尝试向框架添加泛型类型:

type
  Browser<T: TfrmBrowser, constructor> = class
  class function BrowseForm(Owner: Tcomponent): T;
end;

class function Browser<T>.BrowseForm(Owner: Tcomponent): T;
var
_browseForm: T;
begin
  _browseForm := T.Create; // 1st problem T.Create(Owner); throws a comile error
  Result := _browseForm;
end;

然后在选择器框架中,我公开了可以从主机表单的创建事件中调用的 Start :

procedure TPickerFrame.Start<T>(const idProp, nameProp, anIniSection: string; aDto: IDto);
begin
    _browseForm:= Browser<T>.BrowseForm(self);
    _iniSectionName:= anIniSection;
    _idField:= idProp;
    _descriptionField:= nameProp;
    _dto := aDto;
end;

事实是,我在 Delphi 中并没有真正获得泛型,而且这些都不起作用。以下是框架的摘录:

_browseForm: TfrmBrowser;

procedure TPickerFrame.Browse(var DS: TDataSet; var Txt: string; var mr: TModalResult);
begin
  // How do I achieve this with Generics
  // _browseForm := T.Create(nil); // <-- this line is what needs to know the form type at runtime
  // Everything else from here is the same
  _browseForm.ProductName := Application.Title;
  _browseForm.PageSize := 20;
  _browseForm.DatabaseType := bdbtADO;
  _browseForm.ADOConnection := dmdbWhereHouse.BaseADOConnection;
  _browseForm.INISectionName := _iniSectionName;
  _browseForm.DoSelBrowse(DS, Txt, mr, _descriptionField, _text);
  if mr = mrOk then
    begin
      DoSelect(DS);
    end;
end;

有没有人有类似要求的经验?任何帮助,将不胜感激。谢谢

以下是机架主浏览器的示例:

type
  TfrmMbfRACK_MASTER = class(TMxfrmBrowseHoster)
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    //...
  private
    FWHID: Integer;
    procedure SetWHID(const Value: Integer);
    { Private declarations }
  public
    { Public declarations }
    procedure BuildADO(Sender: TObject; Q: TADOQuery); override;
  end;

implementation

{$R *.DFM}

{ TfrmMbfRACK_MASTER }

procedure TfrmMbfRACK_MASTER.FormCreate(Sender: TObject);
  begin
    inherited;
    fmeMxFrmBrowseHoster1.KeyField := 'RACK_ID';
    // FWHID := -2; // 22/06/04
    FWHID := 0; // 22/06/04
  end;

procedure TfrmMbfRACK_MASTER.BuildADO(Sender: TObject; Q: TADOQuery);
  begin
    Q.Close;
    Q.SQL.Clear;
    Q.SQL.Add(
      'SELECT R.RACK_DESC, R.RACK_BARCODE, W.ERP_WH, WC.CLASS_NAME, W.DESCRIPTION WAREHOUSE, R.RACK_PACKING_ORDER,  ');
    //...
  end;

基类

type
  TMxfrmBrowseHoster = class(TfrmMxForm)
  protected
    // ...
    procedure FormCreate(Sender: TObject);
    procedure BuildADO(Sender: TObject; ADOQ: TADOQuery); virtual; abstract;
  public

  procedure TMxfrmBrowseHoster.FormCreate(Sender: TObject);
  begin
    TMxFormProductName := Application.Title;
    fmeMxFrmBrowseHoster1.Initialise;
    INISectionName := Name;
    AbortAction := False;
    fmeMxFrmBrowseHoster1.OnSelect := SelectNormaliser;
    fmeMxFrmBrowseHoster1.OnNeedADO := BuildADO;
    fmeMxFrmBrowseHoster1.INISectionName := self.Name;
    fmeMxFrmBrowseHoster1.MultiSelect := dxBarLargeButton10.Down;
    fmeMxFrmBrowseHoster1.AutoSaveGrid := True;
    dxBarEdit1.OnChange := ActPageSizeChangedExecute;
    FormStorage.RestoreFormPlacement;

    ActConfirmDelete.Execute;
  end;
4

1 回答 1

2

我发现你的问题有点模糊,我不是 100% 确定我完全理解你在问什么。但是,我知道在调用构造函数时如何处理您的问题。也许这就是你需要帮助的全部。

您需要使用虚拟构造函数多态性和一些转换:

class function Browser<T>.BrowseForm(Owner: Tcomponent): T;
var
_browseForm: T;
begin
  _browseForm := TfrmBrowser(T).Create(Owner); 
  Result := _browseForm;
end;

这依赖于虚拟构造函数多态性。因此,您必须确保每个派生类的每个构造函数都TfrmBrowser标有该override指令。

于 2012-09-03T16:34:00.340 回答