0

Delphi 2010 VCLプロジェクトでエンティティを検索するために使用するTFrameがあります。TFrameには、ユーザーが特定のフォームを開いてそのエンティティを参照できるようにするボタン編集があります。(すべてのブラウズフォームは、共通のベースブラウズフォームから継承します)現在、ベースフレームから継承することでこれを実現し、特定のフォームを起動するブラウズイベントを実装しています。毎回の唯一の違いは、クリックイベントに表示されるフォーム(タイプ)です。ジェネリックでこれを実現する方法はありますか。そうすれば、エンティティごとに同じコードを書き直すことなく(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;

次に、ピッカーフレームで、ホストフォームのcreateイベントから呼び出すことができる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 に答える