在对象检查器上显示 TFrame 后代的附加属性

发布于 2024-07-09 02:33:37 字数 2497 浏览 7 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不喜欢何必死缠烂打 2024-07-16 02:33:37

您正在为您的框架注册哪个自定义模块类?
您使用的是哪个版本的 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 的新后代以包含在项目中,并在对象检查器中编辑其已发布的属性,将这个新后代的实例放在 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:

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.

My FrameTest unit is very simple, it has no FrameTest.dfm, only the declaration of the new TFrame descendant:

unit FrameTest;

interface

uses
  Forms;

type
  TTestFrame = class(TFrame)
  private
    FHello: string;
  published
    property Hello: string read FHello write FHello;
  end;

implementation

end.

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.

反目相谮 2024-07-16 02:33:37

不需要以“黑客方式”进行操作

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 元类,而不是 TDataModuleCustomModule

。 其他现有元类名称:

TCustomFormCustomModule

TIDESourceModuleCustomModule

There is no need to do in "hack way"

uses
...
  DMForm,
  VCLFormContainer,
...

procedure Register;
begin
...
  RegisterCustomModule(TYourFrameClass, TFrameModule);   // for frames
  RegisterCustomModule(TYourModuleClass, TDataModuleCustomModule);   // for data modules
...
end;

There is another way around to add frames too

type
  TNestableWinControlCustomModule = class (TWinControlCustomModule)
  public
    function Nestable: Boolean; override;
  end;

function TNestableWinControlCustomModule.Nestable: Boolean;
begin
  Result := True;
end;

+

  RegisterCustomModule(TYourFrameClass, TNestableWinControlCustomModule);

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

紫罗兰の梦幻 2024-07-16 02:33:37

不,我认为这完全不可能。

当我有类似的需求时,我通常所做的就是简单地将框架后代作为其本身的组件安装。 但是,是的,这样你就失去了很多典型的框架行为(特别是在设计时),例如,你不能再直接操作子组件,并且对框架的​​更改不再自动传播到在设计时使用它的表单 - 你有首先重新编译包含该框架的运行时包。

话又说回来,从 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.

黎歌 2024-07-16 02:33:37
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 在设计时只知道已在其中注册的内容。 这不是一个障碍;而是一个障碍。 这是合乎逻辑的行为。

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;

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:

procedure TBASEFrame.Setstr(const Value: string);
begin
  inherited;
  Edit1.Text := Fstr; 
end;

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文