在对象检查器上显示 TFrame 后代的附加属性
Delphi 对象检查器按设计不显示 TFrame 后代的附加属性。 人们倾向于建议使用一种已知的技巧,该技巧通常用于在对象检查器上显示 TForm 后代的属性。 技巧是:通过设计时包将 TForm 后代的自定义模块注册到 Delphi IDE,例如:
RegisterCustomModule(TMyFrame, TCustomModule);
对象检查器可以用这种方式显示 TFrame 后代实例的附加属性,但它在嵌入表单时会丢失其框架行为。 不可重新设计,不可能为其子组件实现事件,并且它接受子控件(它不能)。 但它在自己的设计区域内表现正常。
看起来,Delphi IDE 专门为 TFrame 提供的那些行为。 它们可能不是通用设施。
有没有其他方法可以在不丢失框架行为的情况下完成此任务?
我正在使用 Delphi 2007
@Tondrej,
请阅读该问题的评论,提前致谢。
框架单元.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.
Delphi object inspector doesn't show TFrame descendants's additional properties by design.
People tend to suggest using a known trick which is commonly used for showing TForm descendant's properties on the Object inspector. The trick is: registering custom module for TForm descendants to Delphi IDE via design time package like:
RegisterCustomModule(TMyFrame, TCustomModule);
The object inspector can show additional properties of the TFrame Descendant's instance with this way but it loses its frame behaviours while it is embedded in a form. Not redesignable, not possible to implement events for its subcomponents and it accepts child controls (which it musn't). But it behaves normally in its own design area.
Looks like, those behaviours provided by Delphi IDE specially just for TFrame. They problaly are not kind of generic facilities.
Is there any other way to accomplish this without losing frame behaviours ?
I'm using Delphi 2007
@Tondrej,
Read comments for the problem, thanks in advance.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您正在为您的框架注册哪个自定义模块类?
您使用的是哪个版本的 Delphi?
根据我对 Delphi 2007 的实验,似乎有效的自定义模块类是 TFrameModule。 该类包含在 delphivclide100.bpl 中。 由于没有相应的delphivclide.dcp,您必须手动加载它:
我的FrameTest单元非常简单,它没有FrameTest.dfm,只有新的TFrame后代的声明:
使用TFrameModule类,到目前为止一切似乎都工作正常。 我可以创建 TTestFrame 的新后代以包含在项目中,并在对象检查器中编辑其已发布的属性,将这个新后代的实例放在 IDE 中的表单上,在对象检查器中编辑其新的已发布属性,为以下对象编写事件处理程序它们的子组件等。在 .dfm 资源中,我可以看到实例的预期“内联”指令。
到目前为止我还没有遇到任何问题,所以也许这就是解决方案。
Which custom module class are you registering for your frame?
Which version of Delphi are you using?
From my experiments with Delphi 2007, the custom module class which seems to work is TFrameModule. This class is contained in delphivclide100.bpl. Since there is no corresponding delphivclide.dcp you have to load it manually:
My FrameTest unit is very simple, it has no FrameTest.dfm, only the declaration of the new TFrame descendant:
Using TFrameModule class, everything seems to work fine so far. I can create a new descendant of TTestFrame to include in the project and edit its published properties in the Object Inspector, put instances of this new descendant on a form in the IDE, edit their new published properties in the Object Inspector, write event handlers for their child components etc. In the .dfm resource I can see the expected "inline" directive for the instances.
I haven't encountered any problem with it so far so perhaps this is the solution.
不需要以“黑客方式”进行操作
还有另一种方法可以添加框架
+
单元名称(在XE7中测试):
TCustomModule => 设计编辑器
TDataModuleCustomModule => DMForm (designide.dcp)
TWinControlCustomModule => WCtlForm (designide.dcp)
TFrameModule => VCLFormContainer (vcldesigner.dcp)
我想对于 FireMonkey 应该可以以类似的方式(找到 fmxdesigner.dcp > & 检查 Notepad++ 中的内容)
PS。 在较旧的 Delphi 版本中,DMDesigner 单元中存在 TDataModuleDesignerCustomModule 元类,而不是 TDataModuleCustomModule
。 其他现有元类名称:
TCustomFormCustomModule
TIDESourceModuleCustomModule
There is no need to do in "hack way"
There is another way around to add frames too
+
Names of units (tested in XE7):
TCustomModule => DesignEditors
TDataModuleCustomModule => DMForm (designide.dcp)
TWinControlCustomModule => WCtlForm (designide.dcp)
TFrameModule => VCLFormContainer (vcldesigner.dcp)
I suppose that for FireMonkey it should be possible in similar way (find fmxdesigner.dcp & check what is inside in Notepad++)
PS. In older Delphi versions there was TDataModuleDesignerCustomModule metaclass instead of TDataModuleCustomModule in unit DMDesigner
PPS. Other existing metaclass names:
TCustomFormCustomModule
TIDESourceModuleCustomModule
不,我认为这完全不可能。
当我有类似的需求时,我通常所做的就是简单地将框架后代作为其本身的组件安装。 但是,是的,这样你就失去了很多典型的框架行为(特别是在设计时),例如,你不能再直接操作子组件,并且对框架的更改不再自动传播到在设计时使用它的表单 - 你有首先重新编译包含该框架的运行时包。
话又说回来,从 OOP 的角度来看,这还不算太糟糕。 它实际上强化了实现隐藏的概念。 您仍然可以通过框架本身的新属性和方法公开子组件的各个属性和功能。
No, I don't think this is fully possible.
What I usually do when I have similar needs is to simply install the frame descendant as a component of its own right. But yes, that way you lose a lot of the typical frame behaviour (especially at designtime), e.g. you can no longer manipulate sub-components directly and changes to the frame do no longer automatically propagate to forms that use it at designtime - you have to recompile the runtime package that contains the frame first.
Then again, from an OOP-perspective this isn't too bad. It actually enforces the concept of implementation hiding. You can still expose individual properties and functionality of sub-components via new properties and methods on the frame itself.
我认为这是因为它不应该在设计时工作。 您将 TBaseFrame 注册为自定义模块,因此 TBaseFrame 的(而不是它的后代!!!)属性应该在设计时可编辑。 Delphi IDE 只知道您注册的类的已发布属性; 它不知道您在项目中所做的任何后代和覆盖。 为了使代码在设计时工作,您应该将其包含在 TBaseFrame 定义中:
或者(除了 TBaseFrame 之外)将 TMyFrame 定义注册为自定义模块。
尝试理解:Delphi IDE 在设计时只知道已在其中注册的内容。 这不是一个障碍;而是一个障碍。 这是合乎逻辑的行为。
I think it's because it should not work at design time. You registered TBaseFrame as a custom module, so it is the TBaseFrame's (not it's descendants!!!) properties which should be editable at design time. Delphi IDE knows only about published properties of the class you've registered; it doesn't know anything about any descendants and overrides you've made in your project. To make the code work at design time, you should either include it in the TBaseFrame definition:
or (in addition to TBaseFrame) register the TMyFrame definition as a custom module.
Try to understand: Delphi IDE at design time knows only about things that have been registered in it. It's not a handicap; it's logical behaviour.