[proxies.pas怎么了?]关于delphi6以后组件设计包和运行包分开的话题
2006-03-31 12:04
513 查看
function ResourceWin(hurl) { wid = window.open(hurl, "ResourceWin", "toolbar=yes,status=no,directories=no,location=no,scrollbars=yes,width=1000,height=700,resizable=yes","true"); } What ever happened to Proxies.pas? Rating: Ratings: 63 Rate it Abstract: This article illustrates a scheme for properly segregating runtime code from design-time code in Delphi. By Jeff Overcash. One frequent question since Delphi 6 shipped has concerned the disappearance of Proxies.pas from the source. This change is part of a larger trend. Borland chose not to ship DsgnIntf.dcuwith Delphi 5, apparently to force compliance with the Delphi and C++Builder license agreements. The design-time code had been inadvertently used at runtime by many components. In some ways Borland encouraged this behavior: If you use the new component wizard you will see that this wizard creates only one unit, putting both the component skeleton code (runtime) and the Register procedure (design-time) in the same unit. With Delphi 6, Borland has taken the next step. Not only was DsgnIntfreplaced with DesignIntf, but the property editors were also pulled out into DesignEditors, DesignMenus, DesignWindowsand other design-time files. DesignEditorsin particular uses another IDE file named Proxies. (The Proxiescode resides in DesignIDE.bpl.) Needless to say, these changes can result in errors at compile time. If your code is already segregated in terms of runtime versus design-time then the fix is very simple. Open up your design-time package, select the requires folder and hit the Add button. Type designide.dcpand hit OK. Recompile your package and the error should go away. But how can this problem be fixed when design-time and runtime code has been mixed together? DesignIDE.bplis not a redistributable package in Delphi. So even in situations where the "design-time only" package has the component's runtime code and only the component dcu is used, there can still be a problem. In 99.99% of the cases this is actually very easy to fix. Your runtime code isn't actually using the design-time code; things just are not properly segregated. The segregation lines are fairly simple, however. The design-time package should include: All registration statements. All property editors. All Component editors. Should require DesignIDE and each runtime package that holds the components themselves. The runtime package should include: The components themselves only. Optionally, any forms the editors may use IF the component can call the form itself at runtime The only place where there is a little confusion is if the property/component editor uses a form. If that form is available at runtime to the component, it belongs in the runtime package. If it is only available at design-time, it goes in the design-time package. A very common misperception is that the form itself is the editor, but it is not. It is the component editor that calls the form that is the design-time editor. You should get in the habit of always separating your components into two packages even if you only statically link your application, because mixing design-time and runtime code leads to code bloat. Your design-time code can't be executed in the runtime, but the linker doesn't know that so it links it in anyway. (This is why DsgnIntfis trying to get linked in.) Let's walk though a very simple component to see how to break the design-time code from the runtime: { TMixedComponent } TMixedComponent = class(TComponent) private FFileName: String; published property FileName : String read FFileName write FFileName; { Published declarations } end; { TMixedFileNameProperty } TMixedFileNameProperty = class(TPropertyEditor) function AllEqual: boolean; override; procedure Edit; override; function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure SetValue (const Value: string); override; end; procedure Register; implementation procedure Register; begin RegisterPropertyEditor(TypeInfo(string), TMixedComponent, 'FileName', TMixedFileNameProperty); RegisterComponents('Samples', [TMixedComponent]); end; function TMixedFileNameProperty.AllEqual: boolean; var FirstVal: string; i: Integer; begin FirstVal := GetStrValue; Result := True; i := 1; while Result and (i < PropCount) do begin Result := Result and (GetStrValueAt(i) = FirstVal); Inc(i); end; end; procedure TMixedFileNameProperty.Edit; var Dlg: TOpenDialog; begin Dlg := TOpenDialog.Create(Application); try with Dlg do begin Title := 'File for ' + TComponent(GetComponent(0)).Name; FileName:= Value; if Execute then Value := FileName; end; finally FreeAndNil(Dlg); end end; function TMixedFileNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog] end; function TMixedFileNameProperty.GetValue: string; begin Result := GetStrValue; end; procedure TMixedFileNameProperty.SetValue(const Value: string); begin SetStrValue(Value); end; end. The easiest way to segregate the design-time code from runtime code is to take all the code that requires DesignIntf and DesignEditors and put it in its own unit. That unit will need to use the component's unit. The component itself does not have need to know about the IDE editors that will work with it. So for a start, remove the design-time units DesignIntf and DesignEditors from the uses clause component unit and let the compiler/linker tell you which classes need to be moved into their own unit: [Error] MixedComponent.pas(23): Undeclared identifier: 'TPropertyEditor' [Error] MixedComponent.pas(23): Class type required [Error] MixedComponent.pas(24): Method 'AllEqual' not found in base class [Error] MixedComponent.pas(25): Method 'Edit' not found in base class [Error] MixedComponent.pas(26): Undeclared identifier: 'TPropertyAttributes' [Error] MixedComponent.pas(27): Method 'GetValue' not found in base class [Error] MixedComponent.pas(28): Method 'SetValue' not found in base class [Error] MixedComponent.pas(35): Undeclared identifier: 'RegisterPropertyEditor' [Error] MixedComponent.pas(35): Undeclared identifier: 'TMixedFile' [Error] MixedComponent.pas(46): Undeclared identifier: 'GetStrValue' [Error] MixedComponent.pas(49): Undeclared identifier: 'PropCount' [Error] MixedComponent.pas(51): Undeclared identifier: 'GetStrValueAt' [Error] MixedComponent.pas(51): Operator not applicable to this operand type [Error] MixedComponent.pas(64): Undeclared identifier: 'GetComponent' [Error] MixedComponent.pas(65): Undeclared identifier: 'Value' [Error] MixedComponent.pas(75): Undeclared identifier: 'paDialog' [Error] MixedComponent.pas(80): Undeclared identifier: 'GetStrValue' [Error] MixedComponent.pas(85): Undeclared identifier: 'SetStrValue' [Fatal Error] JOComponents.dpk(33): Could not compile used unit 'MixedComponent.pas' The next step is to create a new unit to hold the design-time code. Name it something like MixedComponentReg. Move the Register procedure over to that unit. Now start going through the error messages and start evaluating them. The first error, [Error] MixedComponent.pas(23): Undeclared identifier: 'TPropertyEditor', indicates that the whole class inherits from something in one of the design-time units we removed. This is a clear indication that this is only design-time code and the whole class needs to be moved over to the newly created unit. At this point the runtime package now compiles cleanly (if not, keep pulling design-time code out until it compiles cleanly without errors). Now there is no need for Proxies.pas or any other design-time units for the component to work in your application at runtime. The runtime component unit is much simplified. It looks like this: unit MixedComponent; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type { TMixedComponent } TMixedComponent = class(TComponent) private FFileName: String; published property FileName : String read FFileName write FFileName; { Published declarations } end; implementation end. The final step is to get the component and its property editors compiled into a design-time package and installed into the IDE. Create a new package by doing File | New | Other and select package. Bring up the packages options and select design-time only. Give a descriptive name in the Description field. Select the Requires folder and hit the Add button. In the Requires Package edit box type Designide.dcp and hit OK. Also add the dcp for the runtime package that the component resides in. In this case it was put it in JOComponents.dpk, so JOComponents.dcp is added to the requires section. The requires section has three items: JOComponents, designide and rtl. Finally, select the Contains folder and add MixedComponentReg.pas to the package. We're almost done! Open up MixedComponentReg.pas to add a couple of units in the uses section. Which section depends on whether your component or property editor uses the component in its declaration (more complicated editors sometimes need knowledge of the component). If it does, then add it to the Interface uses clause. If not, put it in the implementation uses. In our example we don't need the information so MixedComponent goes in the implementation uses clause. DesignIntf and DesignEditors belong in the Interface uses. SysUtils, Forms, Dialogs, and Classes are all used internally in different ways in the property editor, so they belong in the implementation section. The final MixedComponentReg looks like this: unit MixedComponentReg; interface uses DesignIntf, DesignEditors; type { TMixedFileNameProperty } TMixedFileNameProperty = class(TPropertyEditor) function AllEqual: boolean; override; procedure Edit; override; function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure SetValue (const Value: string); override; end; procedure Register; implementation uses MixedComponent, SysUtils, Forms, Dialogs, Classes; procedure Register; begin RegisterPropertyEditor(TypeInfo(string), TMixedComponent, 'FileName', TMixedFileNameProperty); RegisterComponents('Samples', [TMixedComponent]); end; function TMixedFileNameProperty.AllEqual: boolean; var FirstVal: string; i: Integer; begin FirstVal := GetStrValue; Result := True; i := 1; while Result and (i < PropCount) do begin Result := Result and (GetStrValueAt(i) = FirstVal); Inc(i); end; end; procedure TMixedFileNameProperty.Edit; var Dlg: TOpenDialog; begin Dlg := TOpenDialog.Create(Application); try with Dlg do begin Title := 'File for ' + TComponent(GetComponent(0)).Name; FileName:= Value; if Execute then Value := FileName; end; finally FreeAndNil(Dlg); end end; function TMixedFileNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog] end; function TMixedFileNameProperty.GetValue: string; begin Result := GetStrValue; end; procedure TMixedFileNameProperty.SetValue(const Value: string); begin SetStrValue(Value); end; end. All that is left is to compile and install the design-time package. The runtime code is now completely segregated from the design-time code. While this is a fairly simple example, the only time it gets a little more complicated is when the property editor uses a form to retrieve the data, and that form is also available at runtime. In those cases the form stays in the runtime package, and the design-time property editor will call that form from the runtime package. If you get in the habit of always having a runtime package for the components and a design-time package for the registration and editors, you won't have any more problems, even if you only intend to statically link in the DCUs. By Jeff Overcash (TeamB). NOTE: The views and information expressed in this document represent those of its author(s) who are solely responsible for its content. Borland does not make or give any representation or warranty with respect to such content. | ||
相关文章推荐
- [深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白(转)
- [读书笔记][深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白
- [读书笔记][深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白
- 刚发现了一个问题,关于vs2005 datagridview的,我发现在设计行标头的HeaderCell.Value的时候要是设置RowTemplate.Height 的值>= 17则行标头的那个黑三角就显示出来了,要是小于17就不能显示了,想问问大家,是怎么回事?
- 关于本游戏的移植 和(怎么把源码在自己的电脑和手机上运行的介绍)
- Delphi 包的设计思想及它与PAS、BPL、DCU、DLL、OXC的关系。
- 1181链表最好先插入再排序,刚开始边插入边排序不知道怎么出现了错误,以后尽量插入排序分开吧
- 关于Delphi 下indy Telnet 组件生成com的问题
- delphi窗体动态设计 在系统运行时动态更改控件属性
- delphi中的.dpr、.pas和.dfm文件都怎么解释?
- 怎么在程序运行的时候出现和DELPHI下一样的调试信息???
- 推荐一本关于组件设计的好书
- 关于微软hyper-v怎么在windows客户端上运行
- 请教:如何限制C++.net托管组件在设计时不能运行?
- 关于专题设计,你怎么看?
- 关于把设计时代码从运行时代码中分离出来的问题
- 关于组件(包括控件)设计的一些建议
- 关于大数据领域各个组件打包部署到集群运行的总结(含手动和maven)(博主推荐)
- 用delphi关于财务的日结平衡和月平衡怎么实现.
- 关于oracle32位64位组件运行问题