自定义DataModule打破了Delphi中的继承

时间:2014-02-04 02:41:42

标签: delphi inheritance custom-component

我有一个自定义DatModule(比如TMyDataModule),我希望添加一个已发布的属性(枚举类型),以便可以在Object Inspector中访问该属性(至少对于后代)。

我将该单元添加到现有的设计时包中,并添加了注册码,如“RegisterCustomModule(TMyDataModule,TCustomModule);”;卸载,重建,重新安装包。

当我打开通过继承自TMyDataModule创建的现有DataModule时,该属性显示在OI中。到目前为止一切都很好。

但是,通过继承TMydataModule创建的任何现有(或新创建的)DM,一旦创建,就不再继承TMyDatModule。如果我为任何这些后代编辑DFM并尝试将打开的“对象”更改回“继承”,Delphi会在退出DFM时将其更改回来。

在TMyDataModule上定义的组件在设计时不再出现在“表单”上,并且不能引用它们,例如设置属性等时(可以在代码中访问它们,但是......)

根据要求,举个例子。

这是父类(= TMyDataModule“):

  TdmSQLBase = class(TDataModule)
    sspMeta: TSQLStoredProc;
    dspMeta: TDataSetProvider;
    cdMeta: TClientDataSet;
    dsMeta: TDataSource;
    conMeta: TSQLConnection;
    cdAllIndexes: TClientDataSet;
    sdsMeta: TSQLDataSet;
    procedure DataModuleCreate(Sender: TObject);
    procedure SQLConnectionBeforeConnect(Sender: TObject);

    procedure CDSAfterPost_Upd(DataSet: TDataSet);
    procedure CDSBeforeClose(DataSet: TDataSet);
    procedure CDSBeforeRefresh(DataSet: TDataSet) ;

    ......................  etc etc etc ....................
  published
    property DBApplication : TDBApplication read FDBApplication write FDBApplication default daHeadOffice ;
  end;

var
  dmSQLBase: TdmSQLBase = nil;

This is a descendant originally inherited from the above:


type
  TdmDBCheck = class(TdmSQLBase)
    cddata: TClientDataSet;
    dspData: TDataSetProvider;
    sdsData: TSQLDataSet;
    conData: TSQLConnection;
    dsData: TDataSource;
    cdDatabase: TClientDataSet;
    dsDatabase: TDataSource;
    dspDataBase: TDataSetProvider;
    sdsDatabase: TSQLDataSet;
    dspIndex: TDataSetProvider;
    conINdex: TSQLConnection;
    sdsIndex: TSQLDataSet;
    cdIndex: TClientDataSet;
    dsIndex: TDataSource;
    cdAllTest: TClientDataSet;

    ............... etc etc etc .....
  end;

var
  dmDBCheck: TdmDBCheck;

现在,在注册自定义模块之前,可以在设计时例如指定sdsData的SQLconnection属性来表示在父对象上定义的conMeta(并且它将在连接的下拉列表中显示为“conMeta”)。 (让我们不要深入了解这样做。)在注册了自定义模块后,conMeta不会出现在后代的OI中。但是,dmSQLBase.conMeta可以。但是选择这个可能会在运行时给出一个AV,除非一个人单独实例化它 - 这相当失败了目的并且无论如何都是yukky。

问题不是很大,对于一些现有的后代,他们的DFM将在上面的例子中包含像“conMeta”这样的引用。随着模块的注册,delphi会丢弃/忽略 那些引用因为它们是“无效的”(因此它们在运行时变为零指针)。

我实际上认为注册模块的行为是“更干净”。 (像conMeta这样的组件也不会出现在孩子的“形式”上,这是一个加号)。 但如果我保留注册,我需要找到并更正任何此类引用,我只想了解到底是怎么回事。

1 个答案:

答案 0 :(得分:0)

在我看来,缺少的是注册库专家。在您的设计时间包中,您应该按如下方式注册您的图书馆专家:

RegisterLibraryExpert(TNewMyDataModuleExpert.Create); // <-- Your library expert
RegisterCustomModule(TMyDataModule, TCustomModule);

程序RegisterLibraryExpert位于ExptIntf单元中,因此您必须将其添加到使用条款中。

库专家是一个IDE附加组件,它在Delphi New Items窗口中创建一个新项目。它将允许您为新的IDE模块(新的.pas后代)正确生成单元(.dfmTDataModule文件)。

TNewMyDataModuleExpert是一个声明如下的类:

TNewMyDataModuleExpert = class(TIExpert)
  procedure Execute; override;
  function GetAuthor: string; override;
  function GetComment: string; override;
  function GetGlyph: HICON; override;
  function GetIDString: string; override;
  function GetName: string; override;
  function GetMenuText: string; override;
  function GetPage: string; override;
  function GetState: TExpertState; override;
  function GetStyle: TExpertStyle; override;
end;

TIExpertExptIntf中声明。大多数覆盖方法的目的是将此专家与IDE紧密集成。但是,Execute方法是最重要的方法,可能有这样的实现:

procedure TNewMyDataModuleExpert.Execute;
var
  creator: TMyDataModuleCreator;
  modIntf: TIModuleInterface;
begin
  modIntf := nil;
  creator := TMyDataModuleCreator.Create;
  try
    modIntf := ToolServices.ModuleCreate(creator, [cmAddToProject, cmShowSource,
                                                   cmShowForm, cmUnNamed]);
  finally
    modIntf.Free;
    creator.Free;
  end;
end;

请注意,此处还有另一个类TMyDataModuleCreator。这个负责最终创建新模块,并声明如下:

TMyDataModuleCreator = class(TIModuleCreator)
  function Existing: Boolean; override;
  procedure FormCreated(Form: TIFormInterface); override;
  function GetAncestorName: string; override;
  function GetFileName: string; override;
  function GetFileSystem: string; override;
  function GetFormName: string; override;
  function NewModuleSource(const UnitName, Form, Ancestor: string): string; override;
end;

TIModuleCreatorEditintf中声明。这里最重要的方法是NewModuleSource,它应返回您希望为新模块生成的源代码。您在此处返回的内容将是新生成的单元的确切源代码。例如,您可以添加注释,特定使用条款或任何您喜欢的内容。

另一个重要的方法是GetAncestorName什么应该返回字符串'MyDataModule',而没有通常的T前缀。

就我而言,Existing方法始终返回False。对不起,但此刻我不记得为什么。其他string返回方法返回一个空字符串。

如果需要,FormCreated方法允许您对刚刚创建的对象执行操作。

我想这对你有用!