Pregunta

He utilizado marcos en Delphi durante años, y son una de las características más potentes de la VCL, pero el uso estándar de ellos parece tener un cierto riesgo, tales como:

  1. Es fácil de mover accidentalmente o editar el marco de sub-componentes en forma de host de un marco sin darse cuenta de que son 'retoques' con el marco - Sé que esto no afecta al código de trama original, pero por lo general no lo es lo que cabe esperar.

  2. Cuando se trabaja con el marco que todavía está expuesto a sus sub-componentes para la edición visual, incluso cuando ese marco es años de edad y no debe ser tocado.

Así que me puse a pensar ....

  1. ¿Hay una manera de categorizar los componentes de tal manera que sus posiciones están 'bloqueados'? Esto sería útil para las formas acabadas, así como los marcos. A menudo otros desarrolladores vuelven código para mí, donde sólo los límites del formulario han cambiado y aún no tenían la intención de cualquier cambio.

  2. ¿Hay alguna manera de convertir un marco y sus componentes en un solo componente Delphi? Si es así, la parte interna del bastidor serían completamente ocultos y su capacidad de utilización aumentarían aún más.

Estoy interesado en cualquier pensamiento ...

Brian.

¿Fue útil?

Solución

El registro de sus marcos como un componente resuelve ambos 1. y 2 .:

  1. los componentes en el marco está bloqueado cuando se pone que el control de marco en una forma u otra trama
  2. obtendrá un componente (en realidad: control) que se puede diseñar visualmente

Pero: hay algunas capturas (que pueden ser resueltos, ver link artículo), de los cuales el más importante es la siguiente:

Cuando se pone los componentes en su marco, y luego deja caer ese marco como un componente en un formulario Delphi o marco, los componentes son visibles en el panel Estructura.

El problema es que debido a que son visibles en el panel de estructura, puede eliminarlos, causando violaciónes de acceso.

El truco para resolver este a no se olvide de la 'puntilla' .
Aprendí que valiosa lección de Ray Konopka durante DelphiLive 2009.

Desde la lección es tan valioso, que escribió un entrada de blog en él que se describe en detalle.

La parte esencial es esta pequeña pieza de código (más detalles en el 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

Otros consejos

Sí, sólo se registran como componentes. : -)

El diseño de su marco normalmente y después de este registrarlo. También asegúrese de que no tienen dependencias no deseadas en diferentes unidades, ya que estos están vinculados cuando su 'componente' se utiliza. También se pueden añadir propiedades published con el fin de utilizarlos en el inspector de objetos más tarde. Véase, por ejemplo, el siguiente código generado por el IDE (véase 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;

Compilar lo anterior en un paquete de su elección, instalarlo y que compruebe paleta de componentes. : -)

HTH

Sólo por el aumento de contribución, tenga en cuenta que si vas a la ventana Structure y haga clic derecho en el nombre TFrame que haya elegido, y haga clic en la opción de menú Add to Palete. Esto hará una salida componente de su marco y usted no necesitará crear cualquier procedimiento Register. ; -)

Estoy casi siempre la creación de instancias de marco en el código. Esto es fácil y funcionaba bien para mí hasta ahora.

También se encontró con ese problema cuando se trata de utilizar los marcos como componentes. Hay varias posibilidades para solucionar los problemas obvios, pero todos ellos socavan el principio de ocultación de información (todos los subcomponentes del marco se exponen como propiedades publicadas, que significa todo el mundo puede acceder a ellos).

Lo resuelto mediante la implementación de un genérico "de control de trama" componente:

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, la adición de un marco como un 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;
...

Cuando se utiliza este método, el usuario de su componente no verá sus subcomponentes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top