Отображение дополнительных свойств потомка TFrame в инспекторе объектов - PullRequest
9 голосов
/ 14 ноября 2008

Инспектор объектов 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 ]

4 голосов
/ 14 ноября 2008

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

1 голос
/ 23 июня 2016

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

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 в модуле существовал метакласс TDataModuleDesignerCustomModule DMDesigner

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

TCustomFormCustomModule

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

0 голосов
/ 14 ноября 2008

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

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

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

...