taller - Cómo mejorar el uso de Marcos Delphi
tecnica delphi en administracion (6)
Casi siempre estoy creando instancias de marcos en el código. Esto es fácil y funcionó bien para mí hasta ahora.
He usado marcos en Delphi durante años, y son una de las características más poderosas de la VCL, pero el uso estándar de ellos parece tener algún riesgo, como:
Es fácil mover o editar accidentalmente los subcomponentes de cuadros en el formulario de host de un marco sin darse cuenta de que está ''retocando'' el marco; sé que esto no afecta el código de marco original, pero generalmente no es lo que usted querría.
Al trabajar con el marco, aún está expuesto a sus subcomponentes para la edición visual, incluso cuando el marco tiene años y no debe tocarse.
Entonces llegué a pensar ...
¿Hay alguna manera de "agrupar" componentes de modo que sus posiciones estén "bloqueadas"? Esto sería útil para formularios terminados y marcos. A menudo, otros desarrolladores me devuelven el código donde solo han cambiado los límites del formulario e incluso ellos no intentaron ningún cambio.
¿Hay alguna manera de convertir un marco y sus componentes en un solo componente Delphi? Si es así, las partes internas del marco estarían completamente ocultas y su utilidad aumentaría aún más.
Estoy interesado en cualquier pensamiento ...
Brian.
El registro de sus marcos como componente resuelve tanto el 1.o como el 2.
- los componentes en el marco están bloqueados cuando pones ese control de marco en un formulario u otro marco
- obtendrá un componente (en realidad: control) que puede diseñar visualmente
Pero: hay algunas capturas (que se pueden resolver, ver el enlace del artículo), de las cuales la más importante es esta:
Cuando coloca componentes en su marco y luego los suelta como un componente en un formulario o marco Delphi, los componentes son visibles en el Panel de Estructura.
El problema es que, debido a que son visibles en el panel de estructura, puede eliminarlos y causar violaciones de acceso.
El truco para resolver esto es no olvidar la ''ramita'' .
Aprendí esa valiosa lección de Ray Konopka durante DelphiLive 2009.
Como la lección es tan valiosa, escribí una publicación en el blog que la describe en detalle.
La parte esencial es esta pequeña porción de código (más detalles en la publicación del blog):
procedure RegisterFramesAsComponents(const Page: string; const FrameClasses: array of TFrameClass);
var
FrameClass: TFrameClass;
begin
for FrameClass in FrameClasses do
begin
RegisterComponents(Page, [FrameClass]);
RegisterSprigType(FrameClass, TComponentSprig);
end;
end;
Espero que esto ayude.
--jeroen
Para una solución alternativa, ¿puede hacer que los archivos .dfm solo se lean en su control de origen?
Sí, solo regístrelos como componentes. :-)
Diseña tu marco normalmente y luego de registrarlo. También asegúrese de no tener dependencias no deseadas en diferentes unidades ya que están vinculadas cuando se usa su ''componente''. También puede agregar propiedades published
para usarlas en el Inspector de objetos más adelante. Ver por ejemplo el siguiente código generado por el IDE (ver también mis comentarios):
unit myUnit;
uses
...
type
TmyComp = class(TFrame) //set your frame name to be the name your component
ToolBar1: TToolBar; //different components added in the form designer
aliMain: TActionList;
...
published //this section is added by hand
property DataSource: TDataSource read FDataSource write SetDataSource; //some published properties added just for exemplification
property DefFields: string read FDefFields write SetDefFields;
...
end;
procedure Register; //added by hand
implementation
{$R *.DFM}
procedure Register;
begin
RegisterComponents(''MyFrames'', [TmyComp]); //register the frame in the desired component category
end;
Compila lo anterior en un paquete de tu elección, instálalo y comprueba tu paleta de componentes. :-)
HTH
Solo para aumentar la contribución, tenga en cuenta que si va a la ventana de Structure
y hace clic derecho en el nombre de TFrame que eligió, y hace clic en la opción de menú Add to Palete
. Esto hará que un componente salga de tu Marco y no necesitas crear ningún procedimiento de Register
. ;-)
También encontré ese problema cuando trato de usar marcos como componentes. Hay varias posibilidades para solucionar los problemas obvios, pero todos socavan el principio de ocultamiento de la información (todos los subcomponentes del marco se exponen como propiedades publicadas, lo que significa que todos pueden acceder a ellos).
Lo resolví implementando un componente genérico de "control de marco":
unit RttiBrow.Cbde.FrameControl;
interface
uses
Classes, Controls, Forms, Messages, ExtCtrls;
type
TFrameClass = class of TFrame;
TComponentFrame = class (TFrame)
private
function GetClientHeight: Integer;
function GetClientWidth: Integer;
procedure SetClientHeight(const Value: Integer);
procedure SetClientWidth(const Value: Integer);
function GetOldCreateOrder: Boolean;
procedure SetOldCreateOrder(const Value: Boolean);
function GetPixelsPerInch: Integer;
procedure SetPixelsPerInch(const Value: Integer);
function GetTextHeight: Integer;
procedure SetTextHeight(const Value: Integer);
published
{ workarounds for IDE bug }
property ClientWidth: Integer read GetClientWidth write SetClientWidth stored False;
property ClientHeight: Integer read GetClientHeight write SetClientHeight stored False;
property OldCreateOrder: Boolean read GetOldCreateOrder write SetOldCreateOrder stored False;
property PixelsPerInch: Integer read GetPixelsPerInch write SetPixelsPerInch stored False;
property TextHeight: Integer read GetTextHeight write SetTextHeight stored False;
end;
TComponentFrame<TFrameControl: class { TControl }> = class (TComponentFrame)
private
function GetController: TFrameControl; inline;
protected
property Controller: TFrameControl read GetController;
public
constructor Create (AOwner: TComponent); override;
end;
TFrameControl<T: TFrame> = class (TWinControl)
private
FFrame: T;
function PlainFrame: TFrame;
protected
procedure CreateParams (var Params: TCreateParams); override;
property Frame: T read FFrame;
public
constructor Create (AOwner: TComponent); override;
property DockManager;
published
property Align;
property Anchors;
property BiDiMode;
property Color;
property Constraints;
property Ctl3D;
property UseDockManager default True;
property DockSite;
property DoubleBuffered;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property ParentBiDiMode;
property ParentBackground;
property ParentColor;
property ParentCtl3D;
property ParentDoubleBuffered;
property ParentFont;
property ParentShowHint;
property ShowHint;
property TabOrder;
property TabStop;
property Touch;
property Visible;
property OnAlignInsertBefore;
property OnAlignPosition;
property OnCanResize;
property OnConstrainedResize;
property OnDockDrop;
property OnDockOver;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnGesture;
property OnGetSiteInfo;
property OnMouseActivate;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnResize;
property OnStartDock;
property OnStartDrag;
property OnUnDock;
end;
implementation
uses
Windows;
{ TFrameControl<T> }
constructor TFrameControl<T>.Create(AOwner: TComponent);
begin
inherited;
FFrame := T (TFrameClass (T).Create (Self));
PlainFrame.Parent := Self;
PlainFrame.Align := alClient;
end;
procedure TFrameControl<T>.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style or WS_CLIPCHILDREN;
Params.ExStyle := Params.ExStyle or WS_EX_CONTROLPARENT;
end;
function TFrameControl<T>.PlainFrame: TFrame;
begin
Result := FFrame; // buggy compiler workaround
end;
{ TComponentFrame }
function TComponentFrame.GetOldCreateOrder: Boolean;
begin
Result := False;
end;
function TComponentFrame.GetPixelsPerInch: Integer;
begin
Result := 0;
end;
function TComponentFrame.GetTextHeight: Integer;
begin
Result := 0;
end;
procedure TComponentFrame.SetClientHeight(const Value: Integer);
begin
Height := Value;
end;
procedure TComponentFrame.SetClientWidth(const Value: Integer);
begin
Width := Value;
end;
procedure TComponentFrame.SetOldCreateOrder(const Value: Boolean);
begin
end;
procedure TComponentFrame.SetPixelsPerInch(const Value: Integer);
begin
end;
procedure TComponentFrame.SetTextHeight(const Value: Integer);
begin
end;
function TComponentFrame.GetClientHeight: Integer;
begin
Result := Height;
end;
function TComponentFrame.GetClientWidth: Integer;
begin
Result := Width;
end;
{ TComponentFrame<TFrameControl> }
constructor TComponentFrame<TFrameControl>.Create(AOwner: TComponent);
begin
inherited;
Assert (AOwner <> nil);
Assert (AOwner.InheritsFrom (TFrameControl));
end;
function TComponentFrame<TFrameControl>.GetController: TFrameControl;
begin
Result := TFrameControl (Owner);
end;
end.
Con esta clase, agregar un marco como componente se convierte en un proceso de dos etapas:
// frame unit
type
TFilteredList = class;
TFrmFilteredList = class (TComponentFrame<TFilteredList>)
// lots of published sub-components and event methods like this one:
procedure BtnFooClick(Sender: TObject);
end;
TFilteredList = class (TFrameControl<TFrmFilteredList>)
private
procedure Foo;
public
// the component''s public interface
published
// the component''s published properties
end;
procedure Register;
...
procedure Register;
begin
RegisterComponents (''CBDE Components'', [TFilteredList]);
end;
procedure TFrmFilteredList.BtnFooClick(Sender: TObject);
begin
Controller.Foo;
end;
procedure TFilteredList.Foo;
begin
end;
...
Al usar este enfoque, el usuario de su componente no verá sus subcomponentes.