在对象检查器上显示TFrame后代的其他属性

时间:2008-11-14 10:02:26

标签: delphi tframe

Delphi对象检查器未按设计显示TFrame后代的其他属性。 人们倾向于建议使用一种已知的技巧,这种技巧通常用于在对象检查器上显示TForm后代的属性。诀窍是:通过以下设计时间包将TForm后代的自定义模块注册到Delphi IDE:

RegisterCustomModule(TMyFrame, TCustomModule);

对象检查器可以用这种方式显示TFrame Descendant实例的其他属性,但是当它嵌入到表单中时,它会丢失框架行为。不可重新设计,不可能为其子组件实现事件,并且它接受子控件(它没有)。但它在自己的设计领域表现正常。

看起来,这些行为是由Delphi IDE专门为TFrame提供的。它们可能不是通用设施。

有没有其他方法可以在不丢失帧行为的情况下实现这一目标?

我正在使用Delphi 2007


@Tondrej,

提前感谢您阅读问题的评论。

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.

4 个答案:

答案 0 :(得分:4)

您为框架注册了哪个自定义模块类? 您使用的是哪个版本的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资源中,我可以看到实例的预期“内联”指令。 到目前为止我还没有遇到任何问题,所以也许这就是解决方案。

答案 1 :(得分:1)

没有必要采用&#34; hack方式&#34;

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 =&gt;的 DesignEditors

TDataModuleCustomModule =&gt; DMForm (designide.dcp)

TWinControlCustomModule =&gt; WCtlForm (designide.dcp)

TFrameModule =&gt; VCLFormContainer (vcldesigner.dcp)

我认为对于 FireMonkey ,它应该可以类似的方式(找到 fmxdesigner.dcp &amp;检查Notepad ++中的内容)

PS。在较旧的Delphi版本中,单位 DMDesigner

中有TDataModuleDesignerCustomModule元类而不是TDataModuleCustomModule

PPS。其他现有的元类名称:

TCustomFormCustomModule

TIDESourceModuleCustomModule

答案 2 :(得分:0)

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

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

然后,从OOP的角度来看,这并不算太糟糕。它实际上强制实现隐藏的概念。您仍然可以通过框架本身的新属性和方法公开子组件的各个属性和功能。

答案 3 :(得分:0)

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在设计时只知道已在其中注册的内容。这不是障碍;这是合乎逻辑的行为。