我有一个自定义DatModule (例如TMyDataModule),我希望向它添加一个已发布的属性(枚举类型),以便在对象检查器中可以访问该属性(至少对后代来说是如此)。
我将该单元添加到现有的设计时包中,并添加了注册代码,如"RegisterCustomModule(TMyDataModule,TCustomModule);";卸载、重建、重新安装包。
当我打开通过继承从DataModule中创建的现有TMyDataModule时,该属性将显示在OI中。到目前一切尚好。
但是,通过从TMydataModule继承来创建的任何现有(或新创建的)DM,一旦创建,它们就不再从TMyDatModule继承。如果我为这些后代中的任何一个编辑DFM,并尝试将开头的"object“更改回"inherited",则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的sdsData属性来表示在父模块上定义的conMeta (并且它将显示在连接的下拉列表中,就像"conMeta")。(我们不要陷入这样做的欲望之中。)注册自定义模块后,conMeta不会出现在子代的OI中。然而,dmSQLBase.conMeta确实如此。但是,选择这一点可能会在运行时给出一个AV,除非单独实例化父服务器--这完全违背了目的,而且仍然是优胜劣汰的。
问题并不大,因为在上面的示例中,对于一些现有的后代,DFM将包含类似于"conMeta“的引用。注册模块后,delphi删除/忽略这些引用,因为它们“无效”(因此它们在运行时成为零指针)。
实际上,我认为注册模块的行为是“更干净”的。(像conMeta这样的组件也不会出现在子组件的“表单”上,这是一个加号)。但如果我保留注册,我需要找到和纠正任何这样的引用,我只是想了解到底是怎么回事。
发布于 2014-02-05 11:16:46
在我看来,您缺少的是注册一个库专家。在您的设计时包中,您应该注册您的库专家如下:
RegisterLibraryExpert(TNewMyDataModuleExpert.Create); // <-- Your library expert
RegisterCustomModule(TMyDataModule, TCustomModule);过程RegisterLibraryExpert位于ExptIntf单元中,因此必须将它添加到uses子句中。
库专家是一个IDE外接程序,它在窗口中创建一个新项。它将允许您为新的IDE模块(新的.pas子代)正确地生成一个单元( TDataModule和.dfm文件)。
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中声明。大多数overriden方法的目的是将该专家紧密集成到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,它应该返回您希望为新模块生成的源代码。您在这里返回的是新生成的单元的确切源代码。例如,您可以添加注释、特定的uses子句或任何您喜欢的内容。
另一个重要的方法是GetAncestorName,它应该返回字符串'MyDataModule',而不使用通常的T前缀。
在我的例子中,Existing方法总是返回False。对不起,但现在我不记得为什么了。其他string返回方法返回空字符串。
如果需要,FormCreated方法允许您对刚刚创建的对象执行操作。
我想这会对你有用的!
https://stackoverflow.com/questions/21542041
复制相似问题