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