首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自定义DataModule在Delphi中中断继承

自定义DataModule在Delphi中中断继承
EN

Stack Overflow用户
提问于 2014-02-04 02:41:42
回答 1查看 1.2K关注 0票数 0

我有一个自定义DatModule (例如TMyDataModule),我希望向它添加一个已发布的属性(枚举类型),以便在对象检查器中可以访问该属性(至少对后代来说是如此)。

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

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

但是,通过从TMydataModule继承来创建的任何现有(或新创建的)DM,一旦创建,它们就不再从TMyDatModule继承。如果我为这些后代中的任何一个编辑DFM,并尝试将开头的"object“更改回"inherited",则Delphi只是在退出DFM时将其更改回来。

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

根据要求举一个例子。

这是父类(=TMyDataModule"):

代码语言:javascript
复制
  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的sdsData属性来表示在父模块上定义的conMeta (并且它将显示在连接的下拉列表中,就像"conMeta")。(我们不要陷入这样做的欲望之中。)注册自定义模块后,conMeta不会出现在子代的OI中。然而,dmSQLBase.conMeta确实如此。但是,选择这一点可能会在运行时给出一个AV,除非单独实例化父服务器--这完全违背了目的,而且仍然是优胜劣汰的。

问题并不大,因为在上面的示例中,对于一些现有的后代,DFM将包含类似于"conMeta“的引用。注册模块后,delphi删除/忽略这些引用,因为它们“无效”(因此它们在运行时成为零指针)。

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

EN

回答 1

Stack Overflow用户

发布于 2014-02-05 11:16:46

在我看来,您缺少的是注册一个库专家。在您的设计时包中,您应该注册您的库专家如下:

代码语言:javascript
复制
RegisterLibraryExpert(TNewMyDataModuleExpert.Create); // <-- Your library expert
RegisterCustomModule(TMyDataModule, TCustomModule);

过程RegisterLibraryExpert位于ExptIntf单元中,因此必须将它添加到uses子句中。

库专家是一个IDE外接程序,它在窗口中创建一个新项。它将允许您为新的IDE模块(新的.pas子代)正确地生成一个单元( TDataModule.dfm文件)。

TNewMyDataModuleExpert是一个声明如下的类:

代码语言:javascript
复制
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中声明。大多数overriden方法的目的是将该专家紧密集成到IDE中。然而,Execute方法是最重要的方法,可能具有如下实现:

代码语言:javascript
复制
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。这个模块负责最终创建新模块,并声明如下:

代码语言:javascript
复制
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,它应该返回您希望为新模块生成的源代码。您在这里返回的是新生成的单元的确切源代码。例如,您可以添加注释、特定的uses子句或任何您喜欢的内容。

另一个重要的方法是GetAncestorName,它应该返回字符串'MyDataModule',而不使用通常的T前缀。

在我的例子中,Existing方法总是返回False。对不起,但现在我不记得为什么了。其他string返回方法返回空字符串。

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

我想这会对你有用的!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21542041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档