Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Como liberar frame (https://www.clubdelphi.com/foros/showthread.php?t=88266)

oscjae 11-05-2015 18:14:21

Como liberar frame
 
Hola, tengo dudas si es correcto eliminar un frame como lo hago, os pongo el ejemplo

Tengo un tipo creado por mi, un registro, y un array abierto de ese registro

Código Delphi [-]
type
  TReg= record
              vCampo1:Real;
              vCampo2:Integer;
              vFrame:TFrame;
            end;
  TLista= array of TReg;

Evidentemente el frame se crea en tiempo de ejecucion, cuando inicializo la variable de tipo TLista hago lo siguiente

Código Delphi [-]

procedure InicializarLista;
var
  i:Integer;
begin
  for i:=0 to Length(vLista)-1 do
    FreeAndNil(vLista[i].vFrame);
  
  SetLength(vLista,0);
end;

Seria correcto liberar el frame de esa forma, gracias!!!

ecfisa 11-05-2015 18:59:22

Hola oscjae.

En líneas generales la idea es correcta, pero para obtener los límites del arreglo dinámico usa las funciones Low y High:

Código Delphi [-]
procedure LiberarLista;
var
  i: Integer;
begin
  for i:= Low( vLista ) to High( vLista ) do
    if Assigned( vLista[i].vFrame ) then
      FreeAndNil( vLista[i].vFrame );

  SetLength( vLista, 0 );
end;

Saludos :)

Lepe 11-05-2015 20:36:21

Respuesta corta: Sí, si todos los frames tienen el mismo Owner.

Respuesta larga: No es aconsejable porque...

Ese código te dará problemas si los frames están en diferentes Owners. Cuando creas el Frame, le tienes que pasar el Dueño que lo destruirá; si se destruye el form, hara un "frame.free" y tu array se queda apuntando a una zona de memoria que ya ha sido liberada, por tanto, al liberar tu array, petará el programa con un "Access Violation". Desde ese que ha petado hasta el final del array, se quedan en memoria porque no han podido liberarse.

PD: Yo odio los arrays, prefiero un TList o TObjectList.

ecfisa 11-05-2015 20:56:23

Hola Lepe.

Es muy acertada tu observación sobre el peligro con los diferentes Owners y dependerá del código de creación ( que no tenemos a la vista ).

Dada la forma en que oscjae hacía la liberación, partí del supuesto que en la creación fijaba a nil como propietario de los frames.

Saludos :)

oscjae 12-05-2015 08:25:03

Esta seria la forma de crearlo

Código Delphi [-]
vLista[vPosicion].vFrame:=TFame.Create(nil);
vLista[vPosicion].vFrame.Parent:=vPanelParent;
vLista[vPosicion].vFrame.Align:=alClient;

El panel en el que lo coloco (vPanelParent) también seria destruido, ya que uso un ScrollBox para ir creando paneles en tiempo de ejecución y colocando dentro los frame, cuando e de eliminar uno por la razón que sea, elimino el frame y también el panel, no se si es la mejor forma de crear un frame en tiempo de ejecución, hasta ahora siempre lo había hecho así.

ecfisa 12-05-2015 13:40:26

Hola oscjae.

Todos los descendientes de TComponent poseen la propiedad Owner que contiene (o no) al componente propietario y esta se determina por el valor pasado al parámetro en la creación. El propietario se encargará de liberar la memoria del componente poseido cuando él mismo sea liberado.

Si fijas la propiedad Owner a nil,
Código Delphi [-]
  Frame := TFame.Create( nil );
estas indicando que no tiene propietario; por lo que liberar la memoria queda bajo tu responsabilidad y es correcto que lo hagas.

Cita:

Empezado por oscjae (Mensaje 492054)
El panel en el que lo coloco (vPanelParent) también seria destruido, ya que uso un ScrollBox para ir creando paneles en tiempo de ejecución y colocando dentro los frame, cuando e de eliminar uno por la razón que sea, elimino el frame y también el panel...

Realmente ahora no se si visualizo claramente la acción, por que van apareciendo nuevos actores como los Panels y el ScrollBox.

Pero, si el Frame debe liberarse cuando lo hace el Panel contenedor, bién podrías hacer al Panel el Owner del frame, delegandole la responsabilidad de su liberación. Y si todo debe destruirse al destruirse el ScrollBox, podrías usar este como Owner... Todo depende del órden en que se vayan creando y se necesiten ir liberando frames y panels.

Saludos :)

oscjae 12-05-2015 18:17:47

Hola ecfisa, la verdad es que como tu dices, todo seria mas sencillo si le doy Owner, el Owner como tu dices seria el panel, el scrollbox nunca se destruye, la idea es ir creando varios TPanel cuando se necesiten, y dentro del panel ira el frame, y claro, también esta la posibilidad de eliminar ese panel, con el frame, claro está, haciéndolo de la forma que tu dices, pasando como parámetro al Create el panel imagino que haciendo un
Código Delphi [-]
FreeAndNil(vPanel)
sería suficiente para no tener que hacer nada con el frame, que lo eliminará su propietario.

Gracias!!!

Lepe 17-05-2015 22:21:08

Llego 5 días tarde, pero en fin, daré mi opinión, ya que me doy por aludido en el tema.

Cuando he estado en una situación similar (scrollBox con Tframes), la forma más rápida de sincronizar ambos es:
- Los frames y paneles con Owner al ScrollBox
- Al borrar un panel, refrescar todo :(, es decir, hacer un scrollbox.DestroyComponents (que no debería usarse... pero está ahí para ser usado :rolleyes: ), y después inicializar el array (poniendo los frames del array a nil, ya que el ScrollBox los liberó). Por ultimo, creo todos los paneles/frames de nuevo.

Otro método (sería lo suyo, pero implica más trabajillo), usar el Notification, me explico:

Cuando un componente del Form se va a liberar, informa a su dueño (si lo tiene) de este hecho, de forma que el dueño, no intentará liberarlo cuando se cierre. Ejemplito:

Un form con un botón y un TEdit, en el botón pones el código "edit1.Free".
Ejecutas el proyecto, pulsas el botón (el Edit desaparece del Form) y cierras el proyecto con la X roja.
No produce ningún error, porque el Edit informó al Form que se iba a liberar y ya el Form lo quitó de su lista de componentes que controla su destrucción.
Si el Form intenta liberar por segunda vez el Edit,daría un Access Violation.

Solo hay un problema: que tu array se entere que el componente frame se ha liberado. Para eso, puedes guardar en el Frame.Tag el índice donde se encuentra en vLista.

No tenemos ese código, pero en algún momento harás algo así:
vLista[n].vFrame := FrameRecienCreada;
pues agregas otra línea:
FrameRecienCreada.Tag := n ;

Y ahora en el form, añades lo siguiente:
Código Delphi [-]
type  TForm1 = class(TForm)
  private
    { Private declarations }
  protected
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;

  public
    { Public declarations }

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Notification(AComponent: TComponent;
  Operation: TOperation);
  var indice: Integer;
begin

// AComponent es el componente del Form que se va a liberar. Todavía está vivo.
// Operation puede ser opInsert (que se va a insertar en el Form) o bien opRemove (que se va a quitar del Form)
  inherited Notification(AComponent, Operation);
  if (AComponet is TFrame) and (operation = opRemove) then begin
    indice := TFrame(Acomponet).Tag;
    vLista[indice].vFrame := nil ;
  end;
end;

Saludos!


La franja horaria es GMT +2. Ahora son las 05:08:49.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi