Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 08-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Post Forms: FreeAndNil ó Release y la validación Assigned?

Hola que tal, bueno tengo un problema al liberar Form creados en tiempo de ejecución, el siguiente codigo me funciona perfectamente:

Código Delphi [-]
  
  {si el Form no esta creado se crea y se muestra, y si le vuelven a dar click al   boton entonces solo lo muestra.}

  if not Assigned(Form_Prueba) then 
  begin
     Application.CreateForm(TForm_Prueba, Form_Prueba);
     Form_Prueba.Show;
  end else begin
    if Form_Prueba.WindowState <> wsNormal  then
      Form_Prueba.WindowState :=  wsNormal;
    Form_prueba.SetFocus ;
  end;

Como esta en modo "Show" se libera el mismo Form desde el evento OnClose con FreeAndNil y funciona bien.

Código Delphi [-]
procedure TForm_Prueba.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  FreeAndNil(Form_Prueba);
end;

Pero si deseo agregar un botón "Salir" en mi Form_Prueba al llamar a "Close" me genera un error... supongo que esto es por que FreeAndNil termina los procesos pendientes... y como OnClose es llamado desde otro evento a pesar de hacer el FreeandNil, regresa a terminar el evento OnClick (esto lo probe poniendo Showmessages y si regresa)

Código Delphi [-]
procedure TForm_Prueba.btnSalirClick(Sender: TObject);
begin
  //Showmessage('');
  close;
  //Showmessage(''); {Este se msg se muestra a pesar del FreeAndNil}
end;

{*************************************************************************************************** ***************}
Anteriormente tenia en el OnClose el llamado a Release, pero al perecer no libera al Form:

Código Delphi [-]
procedure TForm_Prueba.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  release;
end;

por al hacer la siguiente validación, el Assigned alparecer si lo encuentra :

Código Delphi [-]
  
  if not Assigned(Form_Prueba) then 
  ...
  end;

Esto me confunde, ya que se supone que Release internamente hace su propio Free... y lo ocupaba por que el Release sirve para cuando se quiere liberar el mismo Form que lo invoco a diferencia del Free que es para liberar externamente...

La pregunta general es ¿Como puedo liberar correctamente mi Form desde su evento Onclose y desde un botón "Salir" que invoque a Close; Y que respete la validación: ?

Código Delphi [-]
  
  if not Assigned(Form_Prueba) then 
  begin
     Application.CreateForm(TForm_Prueba, Form_Prueba);
     Form_Prueba.Show;
  end else begin
    if Form_Prueba.WindowState <> wsNormal  then
      Form_Prueba.WindowState :=  wsNormal;
    Form_prueba.SetFocus ;
end;

De antemano gracias y ojala puedan ayudarme!
Buen día saludos.
Responder Con Cita
  #2  
Antiguo 08-02-2010
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Debes hacerlo con FreeAndNil ya que éste hace que el formulario se destruya,libere la memoria ocupada y tu formulario Form_Prueba lo ponga en nulo(nil);
Ten en cuenta que el método Release no destruye al formualrio inmediatamente sino que tan solo manda un mensaje (con la API PostMessage y no con SendMessage), a la cola de Mensajes de Windows informandole que debe ser destruido.
Para entender un poco mas la cuestion puedes leer estos otros hilos.--> 1,2 etc. aunque mejor seria si chequeas la Ayuda de Delphi.
saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #3  
Antiguo 08-02-2010
Avatar de look
look look is offline
Miembro
 
Registrado: sep 2007
Ubicación: The Shire
Posts: 656
Poder: 17
look Va camino a la fama
Cita:
Empezado por jbautista Ver Mensaje
Hola que tal, bueno tengo un problema al liberar Form creados en tiempo de ejecución, el siguiente codigo me funciona perfectamente:

Código Delphi [-] {si el Form no esta creado se crea y se muestra, y si le vuelven a dar click al boton entonces solo lo muestra.} if not Assigned(Form_Prueba) then begin Application.CreateForm(TForm_Prueba, Form_Prueba); Form_Prueba.Show; end else begin if Form_Prueba.WindowState <> wsNormal then Form_Prueba.WindowState := wsNormal; Form_prueba.SetFocus ; end;


Como esta en modo "Show" se libera el mismo Form desde el evento OnClose con FreeAndNil y funciona bien.

Código Delphi [-]procedure TForm_Prueba.FormClose(Sender: TObject; var Action: TCloseAction); begin FreeAndNil(Form_Prueba); end;


Pero si deseo agregar un botón "Salir" en mi Form_Prueba al llamar a "Close" me genera un error... supongo que esto es por que FreeAndNil termina los procesos pendientes... y como OnClose es llamado desde otro evento a pesar de hacer el FreeandNil, regresa a terminar el evento OnClick (esto lo probe poniendo Showmessages y si regresa)

Código Delphi [-]procedure TForm_Prueba.btnSalirClick(Sender: TObject); begin //Showmessage(''); close; //Showmessage(''); {Este se msg se muestra a pesar del FreeAndNil} end;


{*************************************************************************************************** ***************}
Anteriormente tenia en el OnClose el llamado a Release, pero al perecer no libera al Form:

Código Delphi [-]procedure TForm_Prueba.FormClose(Sender: TObject; var Action: TCloseAction); begin release; end;


por al hacer la siguiente validación, el Assigned alparecer si lo encuentra :

Código Delphi [-] if not Assigned(Form_Prueba) then ... end;


Esto me confunde, ya que se supone que Release internamente hace su propio Free... y lo ocupaba por que el Release sirve para cuando se quiere liberar el mismo Form que lo invoco a diferencia del Free que es para liberar externamente...

La pregunta general es ¿Como puedo liberar correctamente mi Form desde su evento Onclose y desde un botón "Salir" que invoque a Close; Y que respete la validación: ?

Código Delphi [-] if not Assigned(Form_Prueba) then begin Application.CreateForm(TForm_Prueba, Form_Prueba); Form_Prueba.Show; end else begin if Form_Prueba.WindowState <> wsNormal then Form_Prueba.WindowState := wsNormal; Form_prueba.SetFocus ; end;


De antemano gracias y ojala puedan ayudarme!
Buen día saludos.


Código Delphi [-]
  if not Assigned(Form_Prueba) then 
  begin
     Form_Prueba:= TForm_Prueba.Create(nil);
     Form_Prueba.Show;
  end else begin
    if Form_Prueba.WindowState <> wsNormal  then
      Form_Prueba.WindowState :=  wsNormal;
    Form_prueba.SetFocus ;
  end;




procedure TForm_Prueba.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  freeandnil(Form_prueba);
end;
__________________
all your base are belong to us
Responder Con Cita
  #4  
Antiguo 08-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Gracias rgstuamigo si ya me le voy agarrando el hilo, y el detalle con el Release es que probablemente no lo libere al instante...

Ahora tengo dudas mas especificas...

1: FreeAndNil me funciona bien desde el OnClose, cierra y libera el Form desde el boton para cerrar por default de las ventanas de windows.

Pero en algunos casos, cuando pongo un TBotón "Salir" y en su evento OnClick invovo a Close me genera un error.

2. Assigned es la mejor forma de verificar si un Form ya esta creado???

3. Application.CreateForm(TForm_Prueba, Form_Prueba); es la mejor forma para crear el Form???
Responder Con Cita
  #5  
Antiguo 08-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Hola look lo que me pusiste lo probe y funciona muy bien cuando el Form se cierra desde el botón Cerrar de las vantanas de Windows


Pero si pongo un botón, y en su evento Onclick llamo al método Close, me genera el siguiente error:

"Abstract Error"

¿¿¿Entonces como hago para que cerrar la ventana desde un botón mio y que se ejecute el evento OnClose pero que ya no regrese al OnClick que lo invoco???

Y por otro lado que diferencia hay de crear mi Form con Application.CreateForm(TForm_Prueba, Form_Prueba) a la que tu me sugeriste Form_Prueba:= TForm_Prueba.Create(nil);???

Gracias.
Responder Con Cita
  #6  
Antiguo 08-02-2010
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Cita:
Empezado por jbautista Ver Mensaje
....
Ahora tengo dudas mas especificas...

1: FreeAndNil me funciona bien desde el OnClose, cierra y libera el Form desde el boton para cerrar por default de las ventanas de windows.

Pero en algunos casos, cuando pongo un TBotón "Salir" y en su evento OnClick invovo a Close me genera un error.
Te cuento que he probado colocar un boton en el cual llamo al método Close del formualrio y no he tenido problemas.
Desde luego para mostrar el formulario lo hago asi (Siguiendo tu ejemplo):
Código Delphi [-]
procedure TForm1.Button3Click(Sender: TObject);
begin
 if not Assigned(Form2)then
      Application.CreateForm(TForm2, Form2);
Form2.WindowState:=wsNormal;
Form2.Show;
end;
En el evento OnClose del formulario (Form2 en mi caso) hago esto:
Código Delphi [-]
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(Form2);
end;
Y en un boton que tengo en el formulario 2 (Form2) hago esto:
Código Delphi [-]
procedure TForm2.Button1Click(Sender: TObject);
begin
Close;
end;
Y no tengo problemas....
Quisas en tu caso tienes algun código mas por ahí , que es el causador del error que mencionas..
Cita:
Empezado por jbautista Ver Mensaje
2. Assigned es la mejor forma de verificar si un Form ya esta creado???
Bueno.....si es una forma,en realidad la funcion Assigned lo que hace es Verificar si un puntero o variable es diferente de nulo(nil) algo asi:
Código Delphi [-]
if MiVarible<>Nil then// para el caso de una varible
...
ó
if @MiPuntero<>Nil then//para el caso de un puntero
....
De ahi la importancia de utilizar la funcion FreeAndNil.
Cita:
Empezado por jbautista Ver Mensaje
3. Application.CreateForm(TForm_Prueba, Form_Prueba); es la mejor forma para crear el Form???
Es una forma de hacerlo, en realidad delphi en el archivo .DPR asi lo hace, pero tambien puedes hacerlo de esta forma que es equivalente:
Código Delphi [-]
procedure TForm1.Button3Click(Sender: TObject);
begin
 if not Assigned(Form2)then
      Form2:=TForm2.Create(Application);
Form2.WindowState:=wsNormal;
Form2.Show;
end;
Saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #7  
Antiguo 08-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
rgstuamigo y look :

Pues algo sigue estando raro con mi codigo, voy a checarlo bien.

Mientras probé de esta manera a ver que opinan:

Código Delphi [-]
procedure TForm_principal.btnAbrirClick(Sender: TObject);
var
    i:integer;
    existe:Boolean;
begin

    existe:=False;
    {Recorremos los todos Forms Creados}
    for i := 0 to (Screen.FormCount - 1) do
        {Buscamos si ya existe el Form_Ventana}
        if  Screen.Forms[i].Name = 'Form_Prueba' then begin
            existe:=True;
            break;
        end;
    {Si el Form no existe hay que crear el Form_Ventana}
    if not existe then begin
        Application.CreateForm(TForm_Prueba, Form_Prueba);
        Form_Prueba.Show;
    end else begin
        if Form_Prueba.WindowState <> wsNormal  then
            Form_Prueba.WindowState :=  wsNormal;
        Form_prueba.SetFocus ;
    end;
end;

Y desde el Form_Prueba puedo cerrar de las siguientes maneras sin ningun error hasta el momento:

Código Delphi [-]

procedure TForm_Prueba.BitBtn1Click(Sender: TObject);
begin
  close;
end;

procedure TForm_Prueba.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  release;
end;

De esta forma le ven algún detalle que se me escape???

Con la forma que me recomendaron aun sigo checando si el problema es con la validación:

if not Assigned()

o con la llamada Close desde el evento OnClick del Boton.

Muchas gracias de verdad por su tiempo y comentarios.
Responder Con Cita
  #8  
Antiguo 08-02-2010
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Personalmente no lo veo muy óptimo yo prerferiría usar la funcion assigned en ves de recorrer todos formulario y usar el procedimiento FreeAndNil en lugar de Release tal como te hemos mencionado.
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #9  
Antiguo 09-02-2010
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por rgstuamigo
he probado colocar un boton en el cual llamo al método Close del formualrio y no he tenido problemas
Porque has tenido suerte

Yo hice la prueba del compañero y también obtuve un Access Violation. Luego agregué un tercer formulario al proyecto y "funcionó". O sea que, dependiendo de según qué circunstancias, puedes o no tener un problema.

El punto es, que no puedes usar FreeAndNil en el evento OnClose (y en ningún evento del formulario) por la misma razón que no puedes usar Free y debes usar Release en su lugar.

Tú mismo has observado que Release hace un Post del mensaje CM_RELEASE que, a su vez, genera la llamada a Free. Pero, al hacerse vía un Post, se garantiza que el formulario que se destruye ya ha procesado todos los eventos.

Al usar FreeAndNil e invocar el método Close tal como hace el compañero, el problema está en que el formulario se destruye cuando el evento Button1Click aún no termina.

En todo caso, podría funcionar algo como:

Código Delphi [-]
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  Form2 := nil;
end;

De todas maneras, a mi en lo particular no me gusta este tipo de métodos. Se supone que una clase no debería hacer referencia a ninguna instancia en particular de ella.

Lo que yo hago en estos casos, es usar el mecanismo de notificaciones entre componentes dado por FreeNotification y Notification.

Cuando creo el formulario, uso

Código Delphi [-]
Application.CreateForm(TForm2, Form2);
Form2.FreeNotification(Self);

Esto asegura que Self (el formulario desde donde se abre el segundo formulario) sea notificado cuando Form2 se destruya:

Código Delphi [-]
destructor TComponent.Destroy;
begin
  Destroying;
  if FFreeNotifies <> nil then
  begin
    while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
      TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
    FreeAndNil(FFreeNotifies);
  end;
  DestroyComponents;
  if FOwner <> nil then FOwner.RemoveComponent(Self);
  inherited Destroy;
end;

Entonces, la parte que faltaría, es redefinir el método Notification de TForm1 para, ahí sí, poner en nil la variable:

Código Delphi [-]
procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;

  if (AComponent = Form2) and (Operation = opRemove) then
    Form2 := nil;
end;

// Saludos
Responder Con Cita
  #10  
Antiguo 09-02-2010
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Cita:
Empezado por roman Ver Mensaje
Porque has tenido suerte

Yo hice la prueba del compañero y también obtuve un Access Violation. Luego agregué un tercer formulario al proyecto y "funcionó". O sea que, dependiendo de según qué circunstancias, puedes o no tener un problema.
...
Yo tambien he hecho la prueba nuevamente y he obtenido el error (y si que tuve suerte), la verdad creo que es un comportamiento extraño , ya que si tengo otras controles con algun evento codificado en algunos casos no obtengo dicho error pero en otros si me sale..
De todas formas tambien podriamos solucionarlo(segun mis pruebas) poniendo un componente TBitBtn en lugar del TButton y poner la propiedad Kind=bkClose para que cuando se presione dicho boton el formulario se cierre sin necesidad de codificar nada en su evento OnClick,desde luego ésto me ha funcionado usando FreeAndNil y no he tenido problemas.
Saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #11  
Antiguo 09-02-2010
hach hach is offline
Miembro
 
Registrado: mar 2007
Ubicación: Bariloche, Argentina
Posts: 44
Poder: 0
hach Va por buen camino
Hola,
proba con:

en el evento Close poner solo
Action := caFree;

y en el evento destroy
Form2:=nil;

Saludos
Responder Con Cita
  #12  
Antiguo 09-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Hola rgstuamigo y roman que tal, gracias poco a poco me va quedando claro este asunto, no puedo usar definitivamente FreeAndNil desde el mismo Form... suena logico sobre todo por el asunto de invocar al Close de un evento Click de un Botón.

Al usar el Release lo hace bien por que antes de destruir el Form termina todo los procesos pendientes...

Muy bien entonces las conclusiones son las siguientes:

* Entonces para usar la validación Assigned el Form que se valida necesia estar Liberado y con el punturo a NIL, de aqui la importancia del FreeAndNil

* Assigned pordria no funcionar bien con el Release por que antes de liberar al Form manda los mensajes a una cola de espera y poner el puntero a NIL un tiempo mas tarde, por eso al validar el Assigned podria regresar TRUE aunuqe ya se haya liberado el Form.
Responder Con Cita
  #13  
Antiguo 09-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Hola Roman de lo que sugeriste tengo unas dudas ya que intente aplicarlo y no pude :P

Esta parte no la tengo poner verdad? o si???

Cita:
Empezado por roman Ver Mensaje

Código Delphi [-]
destructor TComponent.Destroy;
begin
  Destroying;
  if FFreeNotifies <> nil then
  begin
    while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
      TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
    FreeAndNil(FFreeNotifies);
  end;
  DestroyComponents;
  if FOwner <> nil then FOwner.RemoveComponent(Self);
  inherited Destroy;
end;

Y en esta no me reconoce el procedure TForm1.Notification me falta alguna declaración en el USES???

Cita:
Empezado por roman Ver Mensaje
Entonces, la parte que faltaría, es redefinir el método Notification de TForm1 para, ahí sí, poner en nil la variable:

Código Delphi [-]
procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;

  if (AComponent = Form2) and (Operation = opRemove) then
    Form2 := nil;
end;

// Saludos

Gracias! Saludos.
Responder Con Cita
  #14  
Antiguo 09-02-2010
Avatar de jbautista
jbautista jbautista is offline
Miembro
 
Registrado: jul 2008
Posts: 43
Poder: 0
jbautista Va por buen camino
Cita:
Empezado por hach Ver Mensaje
Hola,
proba con:

en el evento Close poner solo
Action := caFree;

y en el evento destroy
Form2:=nil;

Saludos
Hola hach lo probe y al parecer funciona bien, incluso invocando al Close desde un Boton del mismo Form...

Me respeta correctamente la validación Assigned y no ha provocado ningún error por el momento :P

Con esto no se queda de basura en memoria o algo así???
El Form se libera bien y el puntero se pone a NIL correctamente al parecer...

Alguien opina algo diferente, algún detalle???
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Assigned y Free gluglu Varios 4 14-05-2007 21:03:37
Problemas FreeAndNil OscarG OOP 4 09-11-2005 12:48:46
Invalid Pointer Operation con Free y Assigned adlfv OOP 3 07-10-2005 00:17:06
Database not assigned!! cwelx Conexión con bases de datos 1 29-09-2004 22:06:40
Left side cannot be assigned to gbece7mx7 Varios 2 29-10-2003 19:01:24


La franja horaria es GMT +2. Ahora son las 10:50:46.


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
Copyright 1996-2007 Club Delphi