Ver Mensaje Individual
  #3  
Antiguo 16-09-2005
Avatar de jmariano
jmariano jmariano is offline
Miembro
 
Registrado: jul 2005
Posts: 376
Reputación: 21
jmariano Va por buen camino
Cita:
Empezado por roman
Queda pendiente los de componentes con nombres en blanco.
Una forma de solucionarlo sería almacenar, en vez del nombre de los componentes, otro valor que identificara de forma única cada componente, como, por ejemplo, un índice.

Para calcular este índice, a la hora de recuperar componentes, tomaríamos como base el índice de nuestro componente, TDoublePanel (ya que el propietario de los controles insertados en nuestros panels va a ser el mismo que el de nuestro componente), y aprovecharíamos el hecho de que los controles se almacenarán de forma consecutiva, en el archivo de recursos .dfm, inmediatamente después de nuestro componente. Para la escritura, lo que podríamos hacer es generar un índice relativo para cada control insertado en los panels, comenzando, por ejemplo, en 0 (teniendo en cuenta que primero se almacena los controles del panel superior y después los del inferior).

Hice una prueba en base a esto y, de momento, parece que funciona bien (tanto en ejecución como en diseño). Aqui os dejo el código completo modificado:

Código Delphi [-]
unit DoublePanel;

interface

uses
  Classes, Controls, ExtCtrls, Forms;

type
  TSubPanel = class(TPanel)
  private
    FDropList: TStringList;

  protected
    property DropList: TStringList read FDropList;

    procedure ReadControls(Reader: TReader);
    procedure SetControls(Root: TComponent);

    procedure WriteControls(Writer: TWriter);
    procedure GetControls(Proc: TGetChildProc; Root: TComponent);

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  TDoublePanel = class(TPanel)
  private
    TopPanel: TSubPanel;
    ClientPanel: TSubPanel;
    IndCtrl: Integer; // Índice relativo para controles insertados
  protected
    procedure CreateWnd; override;

    procedure DefineProperties(Filer: TFiler); override;
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    procedure Loaded; override;

  public
    constructor Create(AOwner: TComponent); override;
  end;

procedure Register;

implementation

uses
  SysUtils, Dialogs;
  
{ TSubPanel }

constructor TSubPanel.Create(AOwner: TComponent);
begin
  inherited;

  TabStop := false;
  FDropList := TStringList.Create;
end;

destructor TSubPanel.Destroy;
begin
  FDropList.Free;
  inherited;
end;

procedure TSubPanel.ReadControls(Reader: TReader);
begin
  FDropList.Clear;
  Reader.ReadListBegin;

  while not Reader.EndOfList do
    DropList.Add(Reader.ReadString);

  Reader.ReadListEnd;
end;

procedure TSubPanel.SetControls(Root: TComponent);
var
  Component: TComponent;
  I, J: Integer;
begin
  inherited;

  { Calculamos el índice para el primero de los controles del panel,
    en el array de componentes perteneciente al propietario de dichos
  controles, según el índice del propietario del panel.  
  
  (Este cálculo se basa en el hecho de que los controles se almacenarán 
  de forma consecutiva despues del propietario del panel) } 
  J := Owner.ComponentIndex + 1; 

  for I := 0 to DropList.Count - 1 do
  begin
    Component := Root.Components[StrToInt(DropList[i]) + J];  

    if Assigned(Component) then
      TControl(Component).Parent := Self;
  end;
end;

procedure TSubPanel.WriteControls(Writer: TWriter);
var
  I: Integer;
begin
  Writer.WriteListBegin;

  // Almacenamos el índice relativo de cada control
  for I := 0 to ControlCount - 1 do 
  begin
  Writer.WriteString(IntToStr(TDoublePanel(Owner).IndCtrl); 
    Inc(TDoublePanel(Owner).IndCtrl);
  end;

  Writer.WriteListEnd;
end;

procedure TSubPanel.GetControls(Proc: TGetChildProc; Root: TComponent);
var
  Control: TControl;
  I: Integer;

begin
  for I := 0 to ControlCount - 1 do
  begin
    Control := Controls[i];

    if Control.Owner = Root then
      Proc(Control);
  end;
end;

{ TDoublePanel }

constructor TDoublePanel.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle - [csAcceptsControls];

  Width := 377;
  Height := 249;
  BevelOuter := bvLowered;

  TopPanel := TSubPanel.Create(Self);
  TopPanel.Align := alTop;
  TopPanel.Parent := Self;

  ClientPanel := TSubPanel.Create(Self);
  ClientPanel.Align := alClient;
  ClientPanel.Parent := Self;
end;

procedure TDoublePanel.CreateWnd;
begin
  inherited;
end;

procedure TDoublePanel.DefineProperties(Filer: TFiler);
begin
  inherited;
  IndCtrl := 0; // Reiniciamos la variable para calcular los índices de los controles
  Filer.DefineProperty('TopPanel', TopPanel.ReadControls, TopPanel.WriteControls, true);
  Filer.DefineProperty('ClientPanel', ClientPanel.ReadControls, ClientPanel.WriteControls, true);
end;

procedure TDoublePanel.GetChildren(Proc: TGetChildProc; Root: TComponent);
begin
  inherited;

  TopPanel.GetControls(Proc, Root);
  ClientPanel.GetControls(Proc, Root);
end;

procedure TDoublePanel.Loaded;
var
  Root: TComponent;

begin
  inherited;

  Root := GetParentForm(Self);

  TopPanel.SetControls(Root);
  ClientPanel.SetControls(Root);
end;

{ Unit methods }

procedure Register;
begin
  RegisterComponents('Samples', [TDoublePanel]);
end;

end.

Comprobareis que ahora si da igual que los componentes tengan nombres o no, ya que siempre los recupera bien y los posiciona correctamente.

(De todas formas, cualquier error que econtréis avisadme!)

Saludos!
Responder Con Cita