Отображение дополнительных свойств потомка TFrame в инспекторе объектов

Инспектор объектов Delphi не отображает дополнительные свойства потомков TFrame. Люди, как правило, предлагают использовать известный прием, который обычно используется для отображения свойств потомка 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 ответа

Какой пользовательский класс модуля вы регистрируете для своего фрейма? Какую версию 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 я вижу ожидаемую "встроенную" директиву для экземпляров. До сих пор я не сталкивался с какой-либо проблемой, так что, возможно, это решение.

Там нет необходимости делать "взломать путь"

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 ++)

PS. В более старых версиях Delphi вместо модуля TDataModuleCustomModule в модуле DMDesigner был метакласс TDataModuleDesignerCustomModule.

PPS. Другие существующие имена метаклассов:

TCustomFormCustomModule

TIDESourceModuleCustomModule

Нет, я не думаю, что это полностью возможно.

Когда я сталкиваюсь с подобными потребностями, я обычно делаю простую установку потомка фрейма в качестве отдельного компонента. Но да, таким образом вы теряете много типичного поведения фрейма (особенно во время разработки), например, вы больше не можете напрямую манипулировать подкомпонентами, а изменения фрейма больше не распространяются автоматически на формы, которые используют его во время разработки - у вас есть сначала перекомпилировать пакет времени выполнения, содержащий кадр.

Опять же, с точки зрения ООП это не так уж плохо. На самом деле это реализует концепцию сокрытия реализации. Вы по-прежнему можете предоставлять отдельные свойства и функциональные возможности подкомпонентов с помощью новых свойств и методов в самом фрейме.

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 во время разработки знает только о вещах, которые были зарегистрированы в нем. Это не гандикап; это логичное поведение.

Другие вопросы по тегам