Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   detener un bucle con un boton cancelar... (https://www.clubdelphi.com/foros/showthread.php?t=2767)

dmariscal 06-08-2003 03:27:05

detener un bucle con un boton cancelar...
 
hola amigos, al momento de oprimir un boton se inicia un bucle, y quiero tener un boton (cancelar) que me cancele o detenga el bucle, mi problema es que al momento de hacer el bucle el deplhi esta en ese proceso (obvio) y no me pela nada, no me permite apretar ningun boton, sabes como hacer para que me deje apretar el boton de cancelar aun cuando esta realizando un bucle??

gracias por la atencion !!:D

nachoasensio 06-08-2003 09:10:05

Hola:

Para que el bucle se pare y atienda los mensajes de windows, puedes hacer en su interior:

Application.ProcessMessages;

Ahora bien, si tu bucle se repite muchas veces y el proceso que se realiza en su interior es muy rápido, esta llamada te lo va a enlentecer mucho. En ese caso es mejor que hagas algo como:

Cont := 0;
Pulsada:= False;

while not (Pulsada) do
begin

// Aquí iría tu proceso
.
.
.

// Sólo se llama a ProcessMessages una vez de cada 100
// iteraciones
if (cont mod 100) = 0 then
begin
Application.ProcessMessages;
end;

INC(cont);
end;





El código del botón Cancelar sería, simplemente,

Pulsada := True;


donde "Pulsada" sería una variable global.

Un saludo.

jachguate 06-08-2003 13:53:01

Solo quiero agregar que cuando llamas a application.processMessages dentro de un bucle, debes tener cuidado con un par de cosas, principalmente deshabilitando controles, pues tu aplicación seguirá respondiendo a todos los mensajes que reciba.
  • Si tenes un usuario "travieso", que presiona diez veces el botón "Procesar", vas a tener en la pila diez procesos corriendo, uno detras de otro, y esto podria provocar problemas serios. Digamos, si es un proceso que aumenta los precios en un 10%, al final vas a tener los precios aumentados en un 159.37%!!!. Además, podrias tener problemas de concurrencia.
  • Si hay controles para parametrizar alguna acción del proceso (como checkboxes, etc) el usuario podria cambar su valor a mitad del proceso, por ejemplo.
  • Otro problema es que el usuario podria cerrar la ventana a medio proceso.

Por lo tanto lo recomendable es deshabilitar todos los controles antes de iniciar el proceso (excepto el botón cancelar) y controlar si se permitirá cerrar la ventana al usuario.

En código, podria ser algo como:

Código:


Type
  TForm1 = Class(TForm)
  ..
  Private
    FEnProceso : Boolean;
    FCancelado : Boolean;
  ..
 
Implementation

Procedure TForm1.bProcesarClick(Sender : TObject);

Var
  i : Longint;

Begin
  FEnProceso := True;
  FCancelado := False;
  try
    InicializarProceso;
    DeshabilitarControles;
    For i := 1 to 2147483647 do
    Begin
      RealizarIteracionDelProceso;
      Application.ProcessMessages;
      if FCancelado Then
          Break; // paramos el proceso
    End;
    if Not FCancelado Then
      ProcesoTerminadoConExito;
    else
      RealizarAccionesParaCancelar;
  finally
    FEnProceso := False;
    HabilitarControles;
  end;
End;

Procedure TForm1.CloseQuery(sender : TObject; var CanClose : Boolean);

Begin
  // evitamos que el usuario cierre la forma mientras se está ejecutando el proceso
  CanClose := not FEnProceso;
End;

Procedure TForm1.bCancelarClick(Sender : TObject);

Begin
  FCancelado := ConfirmaQueQuieraCancelarElProceso;
End;

Espero que la idea te sea de ayuda.

Hasta luego.

;)

dmariscal 06-08-2003 23:08:52

muchas gracias por las respuestas!!
voy a probarlos!

Patxi 13-07-2004 11:21:59

Hola,
oye jachguate, con respecto al ejemplo que has enviado, en

Procedure TForm1.CloseQuery(sender : TObject; var CanClose : Boolean);

Begin
// evitamos que el usuario cierre la forma mientras se está ejecutando el proceso
CanClose := not FEnProceso;
End;


si al pulsar el botón de Salir, FEnProceso no es True, no pasa nada, pero si quiséramos esperar a que FEnProceso sea True y cerrar la aplicación sin tener que pulsar de nuevo, cómo se haría?
Gracias.

jachguate 13-07-2004 11:35:38

Vamos.. un poco de ingenio al asunto... plantea una solución que se te ocurra y si no te funciona yo te echo un cable. Pero hacertelo todo, me resisto. Te has avocado a la persona equivocada :(

Patxi 13-07-2004 12:11:43

Perdona, pero no se trata exactamente de eso, simplemente he utilizado tu respuesta para simplificar. El problema es, siguiendo utilizando parte de tu ejemplo:

Type
TForm1 = Class(TForm)
..
Private
FEnProceso : Boolean;
FCancelado : Boolean;
..

Implementation

Procedure TForm1.bProcesarClick(Sender : TObject);

Var
i : Longint;

Begin
FEnProceso := True;
FCancelado := False;
try
InicializarProceso;
DeshabilitarControles;
For i := 1 to 2147483647 do
Begin
RealizarIteracionDelProceso;
Application.ProcessMessages;
if FCancelado Then
Break; // paramos el proceso
End;
if Not FCancelado Then
ProcesoTerminadoConExito;
else
RealizarAccionesParaCancelar;
finally
FEnProceso := False;
HabilitarControles;
end;
End;

Olvidándonos de los botones de Cancelar y Cerrar y poniendo otro:

TForm1.ClickButton1(Sender: TObject);
begin
.... (CA) Parte del Codigo ...
while FEnProceso do Application.ProcessMessages; ??
begin
.... (CB) Resto del Codigo ...
end;
end;

La pregunta es cómo esperar a que FEnProceso sea False para seguir el código CB es decir que haya terminado el bProcesarClick.


E imaginación le he echado toda la que tengo.

Por cierto, cómo se hace para encerrar el código en una cajita en estos mensajes?

Saludos.

Nuria 13-07-2004 12:52:47

Cita:

Empezado por Patxi
Por cierto, cómo se hace para encerrar el código en una cajita en estos mensajes?

[ delphi ]
.....
Código
....
[ /delphi ]

Sin espacios en blanco entre los corchetes...más información sobre etiquetas .

Saludos! ;)


La franja horaria es GMT +2. Ahora son las 06:08:48.

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