在对象检查器上显示 TFrame 后代的附加属性
Posted
技术标签:
【中文标题】在对象检查器上显示 TFrame 后代的附加属性【英文标题】:Showing TFrame descendant's additional properties on the object inspector 【发布时间】:2010-09-22 07:48:55 【问题描述】:Delphi 对象检查器不会按设计显示 TFrame 后代的附加属性。 人们倾向于建议使用通常用于在对象检查器上显示 TForm 后代属性的已知技巧。诀窍是:通过设计时包将 TForm 后代的自定义模块注册到 Delphi IDE,例如:
RegisterCustomModule(TMyFrame, TCustomModule);
对象检查器可以通过这种方式显示 TFrame 后代实例的其他属性,但它在嵌入表单时会丢失其帧行为。不可重新设计,无法为其子组件实现事件,并且它接受子控件(它不能)。但它在自己的设计区域中表现正常。
看起来,Delphi IDE 专门为 TFrame 提供的那些行为。它们可能不是一种通用设施。
有没有其他方法可以在不丢失帧行为的情况下做到这一点?
我使用的是 Delphi 2007
@Tondrej,
阅读 cmets 的问题,在此先感谢。
frameunit.dfm:
object MyFrame: TMyFrame
Left = 0
Top = 0
Width = 303
Height = 172
TabOrder = 0
object Edit1: TEdit
Left = 66
Top = 60
Width = 151
Height = 21
TabOrder = 0
Text = 'Edit1'
end
end
unit frameunit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TBaseFrame = Class(TFrame)
protected
Fstr: string;
procedure Setstr(const Value: string);virtual;
published
Property str:string read Fstr write Setstr;
End;
TMyFrame = class(TBaseFrame)
Edit1: TEdit;
private
// This won't be called in designtime. But i need this to be called in designtime
Procedure Setstr(const Value: string);override;
end;
implementation
$R *.dfm
TBaseFrame
procedure TBaseFrame.Setstr(const Value: string);
begin
Fstr := Value;
end;
TMyFrame
procedure TMyFrame.Setstr(const Value: string);
begin
inherited;
Edit1.Text := Fstr;
// Sadly this code won't work and Edit1 won't be updated in designtime.
end;
end.
unit RegisterUnit;
interface
procedure Register;
implementation
uses
Windows, DesignIntf, frameunit;
procedure Register;
var
delphivclide: THandle;
TFrameModule: TCustomModuleClass;
begin
delphivclide := GetModuleHandle('delphivclide100.bpl');
if delphivclide <> 0 then
begin
TFrameModule := GetProcAddress(delphivclide, '@Vclformcontainer@TFrameModule@');
if Assigned(TFrameModule) then
begin
RegisterCustomModule(frameunit.TBaseFrame, TFrameModule);
// Just registering that won't cause Tmyframe to loose its frame behaviours
// but additional properties won't work well.
//RegisterCustomModule(frameunit.TMyFrame, TFrameModule);
// That would cause Tmyframe to lose its frame behaviours
// But additional properties would work well.
end;
end;
end;
end.
【问题讨论】:
【参考方案1】:不,我不认为这是完全可能的。
当我有类似需求时,我通常会简单地将框架后代安装为它自己的组件。但是,是的,这样你会失去很多典型的框架行为(尤其是在设计时),例如您不能再直接操作子组件,并且对框架的更改不再自动传播到在设计时使用它的表单 - 您必须首先重新编译包含框架的运行时包。
再说一次,从 OOP 的角度来看,这还不算太糟糕。它实际上强化了实现隐藏的概念。您仍然可以通过框架本身的新属性和方法公开子组件的各个属性和功能。
【讨论】:
【参考方案2】:您为框架注册了哪个自定义模块类? 您使用的是哪个版本的 Delphi?
根据我对 Delphi 2007 的实验,似乎可以工作的自定义模块类是 TFrameModule。该类包含在 delphivclide100.bpl 中。由于没有对应的 delphivclide.dcp 你必须手动加载它:
unit FrameTestReg;
interface
procedure Register;
implementation
uses
Windows, DesignIntf,
FrameTest;
procedure Register;
var
delphivclide: THandle;
TFrameModule: TCustomModuleClass;
begin
delphivclide := GetModuleHandle('delphivclide100.bpl');
if delphivclide <> 0 then
begin
TFrameModule := GetProcAddress(delphivclide, '@Vclformcontainer@TFrameModule@');
if Assigned(TFrameModule) then
RegisterCustomModule(TTestFrame, TFrameModule);
end;
end;
end.
我的FrameTest单元很简单,它没有FrameTest.dfm,只有新TFrame后代的声明:
unit FrameTest;
interface
uses
Forms;
type
TTestFrame = class(TFrame)
private
FHello: string;
published
property Hello: string read FHello write FHello;
end;
implementation
end.
使用 TFrameModule 类,到目前为止一切正常。我可以创建 TTestFrame 的新后代以包含在项目中并在 Object Inspector 中编辑其发布的属性,将这个新后代的实例放在 IDE 中的表单上,在 Object Inspector 中编辑它们新发布的属性,编写事件处理程序他们的子组件等。在 .dfm 资源中,我可以看到实例的预期“内联”指令。 到目前为止我还没有遇到任何问题,所以也许这就是解决方案。
【讨论】:
很好,我已经有一段时间没有使用框架了,因为我认为它们不值得麻烦。但我要试试这个。【参考方案3】:procedure TMyFrame.Setstr(const Value: string);
begin
inherited;
Edit1.Text := Fstr;
// Sadly this code won't work and Edit1 won't be updated in designtime.
end;
我认为这是因为它不应该在设计时工作。您将 TBaseFrame 注册为自定义模块,因此 TBaseFrame 的(不是它的后代!!!)属性在设计时应该是可编辑的。 Delphi IDE 只知道您注册的类的已发布属性;它对您在项目中所做的任何后代和覆盖一无所知。要使代码在设计时工作,您应该将其包含在 TBaseFrame 定义中:
procedure TBASEFrame.Setstr(const Value: string);
begin
inherited;
Edit1.Text := Fstr;
end;
或(除了 TBaseFrame)将 TMyFrame 定义注册为自定义模块。
尝试理解:设计时的 Delphi IDE 只知道其中已注册的内容。这不是障碍;这是合乎逻辑的行为。
【讨论】:
好久不见了。。据我记忆,如果我注册了TMyFrame,它的实例就没有redisegnablity的能力了,它只显示它的后代的属性。【参考方案4】:“破解方式”没必要做
uses
...
DMForm,
VCLFormContainer,
...
procedure Register;
begin
...
RegisterCustomModule(TYourFrameClass, TFrameModule); // for frames
RegisterCustomModule(TYourModuleClass, TDataModuleCustomModule); // for data modules
...
end;
还有另一种添加框架的方法
type
TNestableWinControlCustomModule = class (TWinControlCustomModule)
public
function Nestable: Boolean; override;
end;
function TNestableWinControlCustomModule.Nestable: Boolean;
begin
Result := True;
end;
+
RegisterCustomModule(TYourFrameClass, TNestableWinControlCustomModule);
单位名称(在 XE7 中测试):
TCustomModule => 设计编辑器
TDataModuleCustomModule => DMForm (designide.dcp)
TWinControlCustomModule => WCtlForm (designide.dcp)
TFrameModule => VCLFormContainer (vcldesigner.dcp)
我认为对于 FireMonkey 应该可以采用类似的方式(查找 fmxdesigner.dcp 并检查 Notepad++ 中的内容)
PS. 在较旧的 Delphi 版本中,单元 DMDesigner
中有 TDataModuleDesignerCustomModule 元类而不是 TDataModuleCustomModulePPS. 其他现有元类名称:
TCustomFormCustomModule
TIDESourceModuleCustomModule
【讨论】:
以上是关于在对象检查器上显示 TFrame 后代的附加属性的主要内容,如果未能解决你的问题,请参考以下文章