在对象检查器中显示TFrame派生类的附加属性

11

出于设计考虑,Delphi对象检查器不显示TFrame的子类的附加属性。人们倾向于建议使用一种已知的技巧来显示Object Inspector上TForm子类的属性。这个技巧是:通过设计时包将TForm子类的自定义模块注册到Delphi IDE中。

RegisterCustomModule(TMyFrame, TCustomModule);

对象检查器可以通过这种方式显示TFrame派生类实例的其他属性,但是当它嵌入到一个窗体中时,它会失去它的框架特性。不可重新设计,不可能为其子组件实现事件,并且它接受子控件(这是不应该的)。但是,在其自己的设计区域中,它的行为正常。
看起来,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个回答

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 子类并将其包含在项目中,并在对象检查器中编辑其已发布的属性,在 IDE 中的表单上放置这些新子类的实例,在对象检查器中编辑它们的新已发布属性,为它们的子组件编写事件处理程序等。在 .dfm 资源中,我可以看到预期的“内联”指令的实例。到目前为止,我还没有遇到任何问题,因此这可能是解决方案。

不错,我有一段时间没有使用框架了,因为我认为它们不值得麻烦。但是我将尝试这一个。 - Toon Krijthe

1

不需要用“hack”的方式来做

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 => DesignEditors

TDataModuleCustomModule => DMForm(designide.dcp)

TWinControlCustomModule => WCtlForm(designide.dcp)

TFrameModule => VCLFormContainer(vcldesigner.dcp)

我认为对于FireMonkey,可以以类似的方式实现(查找fmxdesigner.dcp并在Notepad++中检查其中的内容)

附言:在旧版Delphi中,TDataModuleDesignerCustomModule元类的名称是TDataModuleCustomModule。

另外存在的元类名称:

TCustomFormCustomModule

TIDESourceModuleCustomModule


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只知道已经在其中注册的事物。这不是缺陷,而是合乎逻辑的行为。


1
已经过了很长时间...就我所记得的,如果我注册了TMyFrame,它的实例将不再具有可重新设计性,并且它仅显示其后代的属性。 - Serguzest

0

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

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

然而,从面向对象编程的角度来看,这并不太糟糕。实际上,它强制执行了实现隐藏的概念。您仍然可以通过框架本身的新属性和方法公开子组件的个别属性和功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接