我有一个我需要在多个项目中继承的自定义框架。这个框架包含一些代码和一些组件,它位于磁盘上的某个位置,位于它自己的项目目录中。我不想 COPY 它到Object Repository文件夹,这对我来说似乎不对:我最终有两个表单副本,一个在我的Mercurial支持的存储库中,一个在Delphi的Object Repository中。绝对不是个好主意。
我想要的是将我的框架放在一个包中并让包执行使IDE知道框架所需的所有内容,并允许IDE创建给定框架的新兄弟,而不是实际将框架添加到每个框架单个项目。
到目前为止我做了什么,我遇到的问题,我尝试过的解决方案:
RegisterClass
和RegisterNoIcon.
注册我的框架问题:当我进入其他项目并尝试打开派生框架时编辑它说它找不到我的原始框架。RegisterCustomModule(TMyFrameName, TCustomModule)
。 问题:在“其他”项目中,我打开派生框架,IDE不会在原始框架上创建组件,并且IDE抱怨其中一个“继承”组件丢失。InitInheritedComponent(Self, TFrame)
来帮助IDE。这有助于,当我尝试在“其他”项目中打开框架时,所有内容都重新创建,我能够按照我的预期看到框架。 问题:当我保存框架时,它会忘记所有有关继承组件的内容,将每个组件视为添加到此特定框架的新组件。如果我查看保存的DFM,一切都以“对象”开头,没有任何东西以“继承”开头,就像我期望的那样。不幸的是我遇到问题“3”。我尝试深入研究Classes.pas,ToolsAPI,DesignIntf和DesignEditors,但没有找到任何有用的东西。显然,我希望在DFM中看到的“继承”属性是由TWriter在流式传输TComponent之前分配“TWriter.Ancestor”属性时生成的,但是我无法设置它,IDE需要设置它起来。我不能说服IDE为我做这件事。
以下是代码的累积相关部分:
TTestFrame = class(TFrame)
public
constructor Create(Owner:TComponent);override;
end;
constructor TTestFrame.Create(Owner: TComponent);
begin
inherited;
if csDesignInstance in ComponentState then InitInheritedComponent(Self, TFrame);
end;
procedure Register;
begin
RegisterClass(TTestFrame);
RegisterNoIcon([TTestFrame]);
RegisterCustomModule(TTestFrame, TCustomModule);
end;
任何想法,除了“放弃并将你的东西放入对象存储库”? 谢谢!
修改
为什么我需要这样做以及为什么依赖于实际路径名称的解决方案被写入我的项目文件中的原因不起作用:我想支持分支:当一个分支时,合理地期望同一个项目的多个版本是“活着“在同一台机器上的不同目录中。推论,我不能同时在同一个地方有同一个项目的多个版本。
为了确保这项工作,我决定让我的项目不依赖于生活的地方,为了实施这一点,我的团队Clone(Mercurial术语)或Check Out(SVN术语)的每个人都在不同的目录中。我系统上的硬编码路径在我的同事系统中不会很好:如果我们中的任何一个人犯了将任何路径硬编码到应用程序中的错误,那么它不久就会对我们中的一个进行制动,所以错误得到修复。
这当然是我们需要继承的某些库(因此它们不在我们项目的目录中)的一部分的表单和框架的问题!为了在处理这些文件时获得IDE支持,我们需要暂时将它们添加到项目中,我们不必忘记在完成后删除它们。如果我们忘记并推送/检查更改,这些更改将为我们的同事制造构建(因为他们在不同位置检查了库)。
为了解决这个问题,我尝试将这些框架和表单添加到设计时包中(使用完整路径将包加载到IDE中,但路径不是项目文件的一部分,所以没关系)。不幸的是,这失败了,我发布了这个问题。
答案 0 :(得分:3)
这个问题有几个方面:
启用不同的项目分支以使用您自己的软件包的不同版本
D:\\Whatever\\Version1\xxx.bpl
更改为$(MyLib)\\xxx.bpl
。在设计时使用包中的帧
Register;
程序添加到LibraryFrame单元,并将RegisterComponents('MyFrames', [TLibraryFrame]);
放入其实施中。继承包中的框架
既然已经设置了上述所有内容,那么包中的Frame仍然无法继承自“创建”它的库之外的任何其他项目。但是,现在使其可用于继承非常简单。只需将LibraryFrame_fr in 'LibraryFrame_fr.pas' {LibraryFrame},
添加到项目的dpr中,当您使用“Add New | Other”向项目中添加内容时,框架现在将显示在“可继承项目”列表中。
不幸的是,当你选择它时,IDE会抱怨:
Cannot open file "D:\Whatever\SecondFormReusingFrame\LibraryFrame_fr.pas". The system cannot find the file specified.
显然现在需要项目文件夹中的LibraryFrame,而不是试图在MyLib文件夹中找到它。 IDE还会在表单中重新标注TLibraryFrame类型,尽管按住它可以显示正确的文件......
将LibraryFrame_fr in 'LibraryFrame_fr.pas' {LibraryFrame},
更改为
$(MyLib)\LibraryFrame_fr in 'LibraryFrame_fr.pas' {LibraryFrame},
尽管IDE现在不再抱怨没有找到LibraryFrame_fr.pas。但它确实会产生这样的效果:当您保存所有内容时,IDE“友好地”将其更改为相对路径。在我的情况下,..\FrameToBeReusedSecond\LibraryFrame_fr in 'LibraryFrame_fr.pas' {LibraryFrame},
击败了整个练习对象,因为它重新引入了对路径名的依赖,尽管是部分。
然而,将LibraryFrame_fr in 'LibraryFrame_fr.pas' {LibraryFrame},
留在dpr中也不是一个选择。重新加载项目时,即使可以在搜索路径中找到该框架,IDE也会抱怨找不到该框架。
从这个框架派生出来的时候,这样做并忽略IDE投诉,实际上并不是一个选择。 IDE没有添加相应的dfm ...虽然您可以编辑dpr中从MyOwnFrame_fr in 'MyOwnFrame_fr.pas'
到MyOwnFrame_fr in 'MyOwnFrame_fr.pas' {LibraryFrame1}
的用法并手动添加dfm存根,但IDE仍然会因为无法进行操作而感到困惑找到LibraryFrame_fr.pas ...
总而言之,Cosmin似乎IDE只是设置了它想要和期望的东西。我认为您想要的是可以实现的,但前提是您愿意并且能够让您的图书馆文件夹始终与您的项目位于相同的位置。
答案 1 :(得分:1)
呃,简单地将要重用的框架添加到要重复使用的项目中会出现什么问题?
e.g。
修改强>
如果您不想在dpr中包含帧的硬编码路径,则总是存在使用IDE环境变量的策略。
答案 2 :(得分:0)
当我们为我工作的最后一家公司创建构建过程时,我们想做同样的事情。我们使用subversion并为我们的共享组件创建了一个项目,其中包含一个(Finalbuilder)项目来构建我们所有的共享包。
然后我将使用与Marjan(MyLib)变量类似的技术。并从具有最新组件的批处理文件中启动Delphi。
最后我们发现没有必要。我们主要框架的已发布属性变化很少,我们只使用了一套已安装的软件包,如
所示c:\ BDS \ Components \ D12 \ Bpl(这可能与开发人员不同)
但是坐在
中的代码C:\ BDS \ MyProject的\共享 在编译时始终链接,因为这是在构建项目时的相对搜索路径
C:\ BDS \ MyProjectExperimental 在构建时也会使用正确分支的代码。
我们实际上通过使用CodeSmith(代码生成器)生成框架来解决存储库问题,并增加了奖励,它们将被放入正确的命名约定(以及任何特定于分支的更改)的正确文件夹中。我们这样做是为了节省时间,但我们(偶然)一起避免了这个问题。
CodeSmith模板花了一点时间来设置第一帧,但是我们很容易调整它来创建其他子类而没有太多的脑循环(对于诸如dataModules之类的东西)。
cfEditFrame.dfm.cst
<%@ CodeTemplate Language="C#" TargetLanguage="Delphi" Src="" Inherits="" Debug="False" Description="cfEditFrames.dfm Template" ResponseEncoding="ASCII" %> <%@ Property Name="TypeName" Type="System.String" Default="TypeName" Optional="False" Category="Strings" Description="Name of Type. eg Account; AgeMonths" %> inherited cf<%=TypeName%>EditFrame: Tcf<%=TypeName%>EditFrame Width = 425 Height = 63 end
cfEditFrame.cst - 我们必须调用以生成新的子类框架的一个脚本
<%@ CodeTemplate Language="C#" TargetLanguage="Delphi" Src="" Inherits="" Debug="False" Description="cfSDMEditComp Template." ResponseEncoding="ASCII" %> <%@ Property Name="OutputFolder" Type="System.String" Default="..\\SharedNonInstalled" Optional="False" Category="Strings" Description="" %> <%@ Property Name="TypeName" Type="System.String" Default="TypeName" Optional="False" Category="Strings" Description="Name of Type. eg Account; AgeMonths." %> <%@ Register Name="EditFramesPasTemplate" Template="cfEditFrames.pas.cst" %> <%@ Register Name="EditFramesDfmTemplate" Template="cfEditFrames.dfm.cst" %> <%@ Import NameSpace="System.IO" %> <script runat="template"> public override void Render(TextWriter writer) { EditFramesPasTemplate cfEditFramesPasTemplate = new EditFramesPasTemplate(); this.CopyPropertiesTo(cfEditFramesPasTemplate); cfEditFramesPasTemplate.RenderToFile(String.Format("{0}\\Edit\\cf{1}EditFrames.pas", OutputFolder, TypeName), true); EditFramesDfmTemplate cfEditFramesDfmTemplate = new EditFramesDfmTemplate(); this.CopyPropertiesTo(cfEditFramesDfmTemplate); cfEditFramesDfmTemplate.RenderToFile(String.Format("{0}\\Edit\\cf{1}EditFrames.dfm", OutputFolder, TypeName), true); } </script>
可能还有其他源代码生成器也可以这样做,如果不是更好的话。我们有CodeSmith,因此使用它。希望上面的文件格式正常。我是一个新手,有希望渲染像代码的HTML是正确的。
如果要在这些框架上同时拥有属性和组件,则需要执行一项奇怪的操作。您需要分两步完成。首先,您需要在第一个类中添加框架属性,然后在其子类中添加组件。
例如,我们在cfBaseEditFrames.TcfBaseEditFrame中添加自定义属性。
然后我们在cfEditFrames.TcfEditFrame = class(TcfBaseEditFrame)中继承它。 这是我们添加组件的位置(在我们的示例中为TActionList和TImageList)
在包装中注册时,我们添加了
RegisterCustomModule(TcfBaseEditFrame,TWinControlCustomModule);
然后我们确保此包在我们的项目组中,并且打开新的子类帧没有问题。
最后一点,从内存中重要的是后代帧(TcfEditFrame)是添加组件的帧。您无法在TcfBaseEditFrame中添加组件,也无法在TcfEditFrame中添加属性。
BaseEditFrames.pas
unit BaseEditFrames; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TBaseEditFrame = class(TFrame) private { Private declarations } FNewFormProperty: string; published { Published declarations } property NewFormProperty: string read FNewFormProperty write FNewFormProperty; end; implementation {$R *.dfm} end.
BaseEditFrames.dfm
object BaseEditFrame: TBaseEditFrame Left = 0 Top = 0 Width = 320 Height = 240 TabOrder = 0 end
EditFrames.pas
unit EditFrames; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ActnList, BaseEditFrames; type TEditFrame = class(TBaseEditFrame) ActionList: TActionList; private { Private declarations } public { Public declarations } end; implementation {$R *.dfm} end.
EditFrames.dfm
object EditFrame: TEditFrame Left = 0 Top = 0 Width = 320 Height = 240 TabOrder = 0 object ActionList: TActionList Left = 72 Top = 16 end end
FramePackage.dpk
package FramePackage; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} {$RANGECHECKS OFF} {$REFERENCEINFO OFF} {$SAFEDIVIDE OFF} {$STACKFRAMES OFF} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Inheritable Frames'} {$IMPLICITBUILD ON} requires rtl, vcl, designide; contains RegisterFramePackage in 'RegisterFramePackage.pas', BaseEditFrames in 'BaseEditFrames.pas' {BaseEditFrame: TFrame}, EditFrames in 'EditFrames.pas' {EditFrame: TFrame}; end.
unit RegisterFramePackage; interface procedure Register; implementation uses Classes, DesignIntf, WCtlForm, BaseEditFrames; procedure Register; begin RegisterCustomModule(TBaseEditFrame, TWinControlCustomModule); end; end.
您需要安装此设计时包。然后,您可以在另一个项目中拥有一个框架,如下所示
EditFrameDescendants.pas
unit EditFrameDescendants; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, EditFrames, ActnList; type TEditFrameDescendant = class(TEditFrame) Action1: TAction; private { Private declarations } public { Public declarations } end; implementation {$R *.dfm} end.
EditFrameDescendants.dfm
inherited EditFrameDescendant: TEditFrameDescendant ParentFont = False inherited ActionList: TActionList object Action1: TAction Caption = 'Action1' end end end
您应该能够打开EditFrameDescendant,编辑其惊人的“NewFormProperty”并将操作添加到其操作列表中。对我有用....祝你好运