Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Cerrar Formulario (https://www.clubdelphi.com/foros/showthread.php?t=65905)

Red_Leon 21-01-2010 13:43:27

Cerrar Formulario
 
Hola a todos,

Tengo un problema en aplicación que no se si será general o no a ver si me podeis echar una mano:

Es una aplicación de escritorio realizada con Delphi 7 de lo más corriente, en los tiempos de carga (que algunos son elevados), muestro un formulario de espera (de forma normal, .show) con la propiedad FormStyle:=fsStayOnTop y una barra de progreso que se incrementa con un Timer.

Cuando se finaliza el proceso cierro el formulario con FormularioEspera.close.

Si la aplicación ha sido minimizada o ha perdido el foco y en ese tiempo se le manda cerrar el formulario, no se cierra y luego es imposible cerrar el formulario manualmente.

He probado con .close .hide .visible:=false y no lo consigo.

Ocurre tanto en XP, Vista y W7 ¿Alguna idea?

Gracias por adelantado.

salvica 21-01-2010 14:15:35

Hola Red_Leon, todo dependerá si mientras está visble la ventana de espera deseas hacer algo o no.

Si no tienes que hacer nada (solo esperar a que acabe), llámala en modo [/b]ShowModal[/b] y que sea la propia ventana la que se cierre:
- En el evento OnActivate llamas a la función que ejecute lo que desees.
- Al final de la función pones ModalResult := mrOk, para que devuelva la atención a la ventana llamadora, y en ésta ventana la eliminas con Free

Red_Leon 21-01-2010 15:23:50

Lo he probado y la aplicación se bloquea durante el tiempo de espera, pero se cierra.

Y he probado a meter las funciones en hilos pero entonces obtengo el mismo resultado que anteriormente.

Gracias de todas formas salvica.

salvica 21-01-2010 15:37:19

Estoy suponiendo que el form de espera lo llamos desde una ventana, no desde la aplicación al modo de un SplashScreen, no?

Red_Leon 21-01-2010 16:32:37

Se llama desde una ventana, pero si a modo de SplashScreen.

Se utiliza al presentar un informe, la carga de este formulario y un informe de grandes dimensiones puede tardar entre 20 y 30 seg.
Entonces llamo al formulario de Espera, y despues ejecuto la función del informe, para que no se quede bloqueado llamo a Application.ProccessMessage, cuando termina la función del informe llamo a cerrar el Formulario y si la aplicación no tiene el foco de windows (estado minimizado o otra aplicación delante) el Formulario Espera no se cierra, si lo conserva se cierra.

salvica 21-01-2010 17:27:11

Cita:

Empezado por Red_Leon (Mensaje 351411)
Se llama desde una ventana, pero si a modo de SplashScreen.

Se utiliza al presentar un informe, la carga de este formulario y un informe de grandes dimensiones puede tardar entre 20 y 30 seg.
Entonces llamo al formulario de Espera, y despues ejecuto la función del informe, para que no se quede bloqueado llamo a Application.ProccessMessage, cuando termina la función del informe llamo a cerrar el Formulario y si la aplicación no tiene el foco de windows (estado minimizado o otra aplicación delante) el Formulario Espera no se cierra, si lo conserva se cierra.

Me parece que los tiros vienen porque hay algún componente en la ventana que no se ha cerrado.
- Prueba a poner una variable booleana global (por ejemplo CerrarVentana que inicializas a false en el evento OnCreate de la ventana de espera.
- Al finalizar tu función la cambias a true.
- Yo lo que hago es crearlas y eliminarlas cada vez que las necesito, por lo que en tu aplicación pones donde necesites:
Código:

  Application.CreateForm(TForm_Espera, Form_Espera);
  with Form_Espera do begin
      TuFuncion;
        while not CerrarVentana do
              Application.ProcessMessages;
      Hide;
      Free;
  end;

A mi no me da problemas con las SplashScreen, pero si se te sigue colgando puedes probar a poner en el evento OnClose un bucle que te elimine los objetos que tenga la ventana para comprobar cual es el que no ha cerrado completamente

Saludos
salvica

Red_Leon 22-01-2010 09:59:31

No habia intentado el .Free porque me parecia demasiado radical, pero ¡FUNCIONA! puedo el codigo como esta solamente creando y destruyendo el formulario cuando haga falta.

Mucha gracias salvica.

Luego vere a ver que es lo que se esta quedando abierto, ya por curiosidad y por no estar creando y destruyendo formularios.

salvica 22-01-2010 11:35:54

Cita:

Empezado por Red_Leon (Mensaje 351484)
No habia intentado el .Free porque me parecia demasiado radical, pero ¡FUNCIONA! puedo el codigo como esta solamente creando y destruyendo el formulario cuando haga falta.

Mucha gracias salvica.

Luego vere a ver que es lo que se esta quedando abierto, ya por curiosidad y por no estar creando y destruyendo formularios.

Hola Red_Leon, me alegra que funcione

Si Free elimina el formulario sin problemas no creo que quede ningún recurso abierto. Dado que no conozco el código que utilizas, te comento las "dos posibles" causas (pueden haber más) que se me ocurren para que se cuelgue la aplicación:

- Creas el Form_Espera al inicio de la aplicación: Con esto la ventana está disponible en todo el proceso. No se debe eliminar, solo ocultarla (Form_Espera.Show, Form_Espera.Hide). Si haces un Close, es como si la hubieses eliminado (Free) y cuando intentas un Show "casca" porque el form ya no existe

- Creas el Form_Espera cuando le necesitas: La ventana está disponible SOLO a partir de éste momento. Si no la eliminas al finalizar la función que la llama "casca" al crearla de nuevo porque ya existe previamente.

En el foro verás que hay ejemplos que utilizan FreeAndNil en lugar de Free (a secas) para eliminar un formulario de la memoria.

Saludos
salvica

rgstuamigo 22-01-2010 14:34:05

Segun veo puede que el problema vaya por el Timer que tienes corriendo en tu formulario de espera, para lo cual seria muy provechoso si mostraras el código que tienes en el evento OnTimer de tu Timer.;).

Aclarando
un poquito el comentario de salvica, quiero hacerle notar que cuando se cierra un formulario, éste no se destruye ni se libera (Free);) (solo se hace no visible por defecto), a no ser que le indiquemos a delphi que lo libere ;) y es justo para eso el evento OnClose del formulario usando la variable Action de los parametros que tiene dicho evento;
por ejemplo:
Código Delphi [-]
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
Action:=caFree;{<--aqui le estoy indicando a Delphi que cuando
se cierre el formulario se libere ,aunque en realidad no lo 
libera de imnediato, ya que en este caso internamente delphi 
utiliza el metodo Release de los formulario y no el Free que se espera
(ver en la ayuda sobre el metodo Release y el evento OnClose del Form);). 
Si no  se cambia esta variable, simplemente  el formualrio se ocultará (Hide) pero no se liberará. } 
end;
Saludos...:)

salvica 22-01-2010 14:57:03

Cita:

Empezado por rgstuamigo (Mensaje 351515)
...

Aclarando
un poquito el comentario de salvica, quiero hacerle notar que cuando se cierra un formulario, éste no se destruye ni se libera (Free);) (solo se hace no visible por defecto), a no ser que le indiquemos a delphi que lo libere ;) y es justo para eso el evento OnClose del formulario usando la variable Action de los parametros que tiene dicho evento;
...
Saludos...:)

Siempre se aprende algo nuevo :mad: y siempre había creido que cose llamaba internamente a Destroy, a no ser que abortases la operación (con el Action)

Saludos
salvica

rgstuamigo 22-01-2010 15:05:47

Cita:

Empezado por salvica (Mensaje 351517)
Siempre se aprende algo nuevo :mad: y siempre había creido que cose llamaba internamente a Destroy, a no ser que abortases la operación (con el Action)

Saludos
salvica

Eso lo aprendi leyendo este fabuloso articulo del Dr.Marteens y por supuesto revisando el codigo del metodo Close del formulario.;):D:)
Saludos hasta España...:)

Red_Leon 27-01-2010 16:17:10

Cita:

Empezado por rgstuamigo (Mensaje 351515)
Segun veo puede que el problema vaya por el Timer que tienes corriendo en tu formulario de espera, para lo cual seria muy provechoso si mostraras el código que tienes en el evento OnTimer de tu Timer.;).

Aqui va el código

Código Delphi [-]

procedure TForm_Espera.Timer_CambioTimer(Sender: TObject);
begin
  {Aumento del progreso de la 'ProgressBar_Espera'}
  self.ProgressBar_Espera.StepIt;
  {Se comprueba si ha llegado al límite superior}
  if(self.ProgressBar_Espera.Position=self.ProgressBar_Espera.Max) then
  begin
    {Reseteo de la posición de la 'ProgressBar_Espera'}
    self.ProgressBar_Espera.Position:=self.ProgressBar_Espera.Min;
  end;
end;

De momento utilizo el .Create y .Free con el formulario y me va perfecto, pero todavia no he tenido tiempo de porque con .Close no se cerraba, me ha sido más rápido realizar el cambio que ver el porque.

salvica 29-01-2010 17:26:34

Cita:

Empezado por Red_Leon (Mensaje 351987)
Aqui va el código

Código Delphi [-] procedure TForm_Espera.Timer_CambioTimer(Sender: TObject); begin {Aumento del progreso de la 'ProgressBar_Espera'} self.ProgressBar_Espera.StepIt; {Se comprueba si ha llegado al límite superior} if(self.ProgressBar_Espera.Position=self.ProgressBar_Espera.Max) then begin {Reseteo de la posición de la 'ProgressBar_Espera'} self.ProgressBar_Espera.Position:=self.ProgressBar_Espera.Min; end; end;


De momento utilizo el .Create y .Free con el formulario y me va perfecto, pero todavia no he tenido tiempo de porque con .Close no se cerraba, me ha sido más rápido realizar el cambio que ver el porque.

Con esto solo mueves la ProgressBas, pero no se para, por lo que si intentas cerrar el Form te va a dar un error ¿es éste el problema?

Red_Leon 08-02-2010 10:22:07

Antes de cerrar el formulario, paro el Timer y luego llamo a .Close y no se cierra. Ese es el problema original, pero que ya os digo con lo del .Free se solucionaria.


La franja horaria es GMT +2. Ahora son las 16:02:56.

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