我有一个自定义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这样的组件也不会出现在孩子的“形式”上,这是一个加号)。 但如果我保留注册,我需要找到并更正任何此类引用,我只想了解到底是怎么回事。
答案 0 :(得分:0)
在我看来,缺少的是注册库专家。在您的设计时间包中,您应该按如下方式注册您的图书馆专家:
RegisterLibraryExpert(TNewMyDataModuleExpert.Create); // <-- Your library expert
RegisterCustomModule(TMyDataModule, TCustomModule);
程序RegisterLibraryExpert
位于ExptIntf
单元中,因此您必须将其添加到使用条款中。
库专家是一个IDE附加组件,它在Delphi New Items窗口中创建一个新项目。它将允许您为新的IDE模块(新的.pas
后代)正确生成单元(.dfm
和TDataModule
文件)。
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;
TIExpert
在ExptIntf
中声明。大多数覆盖方法的目的是将此专家与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;
TIModuleCreator
在Editintf
中声明。这里最重要的方法是NewModuleSource
,它应返回您希望为新模块生成的源代码。您在此处返回的内容将是新生成的单元的确切源代码。例如,您可以添加注释,特定使用条款或任何您喜欢的内容。
另一个重要的方法是GetAncestorName
什么应该返回字符串'MyDataModule'
,而没有通常的T
前缀。
就我而言,Existing
方法始终返回False
。对不起,但此刻我不记得为什么。其他string
返回方法返回一个空字符串。
如果需要,FormCreated
方法允许您对刚刚创建的对象执行操作。
我想这对你有用!