delphi - Mostrando las propiedades adicionales del descendiente TFrame en el inspector de objetos
(4)
El inspector de objetos Delphi no muestra las propiedades adicionales de TFrame por diseño. La gente tiende a sugerir el uso de un truco conocido que se usa comúnmente para mostrar las propiedades del descendiente de TForm en el inspector de objetos. El truco es: registrar el módulo personalizado para los descendientes de TForm en Delphi IDE a través de un paquete de tiempo de diseño como:
RegisterCustomModule(TMyFrame, TCustomModule);
El inspector de objetos puede mostrar propiedades adicionales de la instancia de TFrame Descendant de esta manera, pero pierde sus comportamientos de marco mientras está incrustado en un formulario. No es redisponible, no es posible implementar eventos para sus subcomponentes y acepta controles secundarios (lo que no debería ser). Pero se comporta normalmente en su propia área de diseño.
Parece, esos comportamientos provistos por Delphi IDE especialmente solo para TFrame. Problaly no son tipo de instalaciones genéricas.
¿Hay alguna otra manera de lograr esto sin perder comportamientos marco?
Estoy usando Delphi 2007
@Tondrej,
Lea los comentarios sobre el problema, gracias de antemano.
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.
No, no creo que esto sea completamente posible.
Lo que suelo hacer cuando tengo necesidades similares es simplemente instalar el descendiente de cuadros como un componente por derecho propio. Pero sí, de esa manera pierde mucho del comportamiento de fotograma típico (especialmente en designtime), por ejemplo, ya no puede manipular subcomponentes directamente y los cambios en el fotograma ya no se propagan automáticamente a los formularios que lo utilizan en el tiempo de diseño. para recompilar primero el paquete de tiempo de ejecución que contiene el marco.
Por otra parte, desde una perspectiva de OOP esto no es tan malo. De hecho, impone el concepto de ocultación de la implementación. Aún puede exponer las propiedades individuales y la funcionalidad de los subcomponentes mediante nuevas propiedades y métodos en el propio marco.
¿Qué clase de módulo personalizado estás registrando para tu marco? ¿Qué versión de Delphi estás usando?
De mis experimentos con Delphi 2007, la clase de módulo personalizado que parece funcionar es TFrameModule. Esta clase está contenida en delphivclide100.bpl. Como no hay un delphivclide.dcp correspondiente, debe cargarlo manualmente:
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.
Mi unidad FrameTest es muy simple, no tiene FrameTest.dfm, solo la declaración del nuevo descendiente TFrame:
unit FrameTest;
interface
uses
Forms;
type
TTestFrame = class(TFrame)
private
FHello: string;
published
property Hello: string read FHello write FHello;
end;
implementation
end.
Usando la clase TFrameModule, todo parece funcionar bien hasta ahora. Puedo crear un nuevo descendiente de TTestFrame para incluirlo en el proyecto y editar sus propiedades publicadas en el Inspector de Objetos, poner instancias de este nuevo descendiente en un formulario en el IDE, editar sus nuevas propiedades publicadas en el Inspector de Objetos, escribir controladores de eventos para sus componentes secundarios, etc. En el recurso .dfm, puedo ver la directiva esperada "en línea" para las instancias. No he encontrado ningún problema hasta ahora, así que tal vez esta es la solución.
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;
Creo que es porque no debería funcionar en el momento del diseño. Usted ha registrado TBaseFrame como un módulo personalizado, por lo que las propiedades de TBaseFrame (¡no los descendientes!) Deberían ser editables en el momento del diseño. Delphi IDE solo conoce las propiedades publicadas de la clase que ha registrado; no sabe nada sobre los descendientes y anulaciones que haya realizado en su proyecto. Para que el código funcione en tiempo de diseño, debe incluirlo en la definición de TBaseFrame:
procedure TBASEFrame.Setstr(const Value: string);
begin
inherited;
Edit1.Text := Fstr;
end;
o (además de TBaseFrame) registre la definición de TMyFrame como un módulo personalizado.
Trate de entender: Delphi IDE en el momento del diseño solo conoce las cosas que se han registrado en él. No es una desventaja; es un comportamiento lógico.
No hay necesidad de hacerlo en "hackear"
uses
...
DMForm,
VCLFormContainer,
...
procedure Register;
begin
...
RegisterCustomModule(TYourFrameClass, TFrameModule); // for frames
RegisterCustomModule(TYourModuleClass, TDataModuleCustomModule); // for data modules
...
end;
Hay otra forma de agregar cuadros también
type
TNestableWinControlCustomModule = class (TWinControlCustomModule)
public
function Nestable: Boolean; override;
end;
function TNestableWinControlCustomModule.Nestable: Boolean;
begin
Result := True;
end;
+
RegisterCustomModule(TYourFrameClass, TNestableWinControlCustomModule);
Nombres de unidades (probado en XE7):
TCustomModule => DesignEditors
TDataModuleCustomModule => DMForm (designide.dcp)
TWinControlCustomModule => WCtlForm (designide.dcp)
TFrameModule => VCLFormContainer (vcldesigner.dcp)
Supongo que para FireMonkey debería ser posible de manera similar (encuentre fmxdesigner.dcp y compruebe qué hay dentro en Notepad ++)
PD. En versiones anteriores de Delphi existía la metaclase TDataModuleDesignerCustomModule en lugar de TDataModuleCustomModule en la unidad DMDesigner
PPS. Otros nombres de metaclase existentes:
TCustomFormCustomModule
TIDESourceModuleCustomModule