Delphi 2010我可以使用具有通用属性和方法的TFrame来传递事件吗?

时间:2012-09-03 16:08:02

标签: delphi generics delphi-2010 tframe

我有一个用于在Delphi 2010 VCL项目中搜索实体的TFrame,在TFrame中我有一个按钮编辑,允许用户打开一个特定的表单来浏览该实体。 (所有浏览表单都从公共基础浏览表单继承) 目前我通过从基础框架继承来实现这一点,然后实现触发特定表单的Browse事件。每次唯一的区别是在click事件上显示的是什么形式(类型),有没有办法可以通过泛型实现这一点。 这样我就可以重用相同的基本框架而不必为每个实体重写相同的代码(超过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;

然后在picker框架中我公开了Start,可以从主机窗体的create事件调用:

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;

1 个答案:

答案 0 :(得分:2)

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

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

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

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