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 29-09-2003
Kaesbu Kaesbu is offline
Registrado
 
Registrado: sep 2003
Posts: 7
Poder: 0
Kaesbu Va por buen camino
Para momentaneamente el programa

Buenas. Me gustaria saber si se puede hacer de alguna forma o no lo siguiente: Resulta tengo mi programa haciendo un bucle y cuando clickeo un boton el programa no me hace caso por que esta haciendo las ordenes del bucle. Se puede para momentaneamente el bucle para que atienda la orden del boton y luego pueda seguir haciendo el bucle???? Muchas gracias.
Responder Con Cita
  #2  
Antiguo 29-09-2003
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¡Buen día!

Kaesbu:

Puedes utilizar el método ProcessMessages del objeto Application, llamándolo al final (y dentro) del ciclo. Por ejemplo:

Código:
For I := 1 To 1000000 Do
Begin
  ...(sentencias)...
  Application.ProcessMessages;
End;
ProcessMessages hace que la aplicación procese todos los eventos pendientes que le han llegado (como teclazos, clicks de ratón, avisos del sistema operativo, etc.). Extrae uno a uno los mensajes de su cola de mensajes pendientes. Cuando ya no hay ninguno que procesar, entonces vuelve y continúa con la rutina donde fue llamado.

Esto permite llevar a cabo ciclos de procesamiento que pueden ser algo lentos, sin que la aplicación deje de responder a las acciones del usuario.

No obstante, debe uno tener cuidado al utilizar el método ProcessMessages, ya que éste puede desencadenar de nuevo el ciclo que actualmente se está ejecutando, resultando en una doble ejecución simultánea del mismo proceso.

Ésto último se podría dar, por ejemplo, al ejecutar el ciclo en el evento OnClick de un botón, y luego durante el mismo, el usuario vuelve a presionar el mismo botón, el cuál es nuevamente accionado gracias a la llamada a Application.ProcessMessages.

Para evitar este problema, existen varias soluciones (como sucede siempre en la programación ). Una de ellas es inhabilitar el botón mientras ejecuta su proceso:

Código:
TForm1.Button1Click (Sender :TObject);
Begin
  Button1.Enabled := False;

  Try
    For I := 1 To 1000000 Do
    Begin
      ...(sentencias)...
      Application.ProcessMessages;
    End;
  Finally  
    { Se uitiliza Try..Finally para asegurar que el botón vuelva a
      habilitarse, aunque se eleve una excepción en el ciclo }
    Button1.Enabled := True;
  End;
End;
Al utilizar ProcessMessages, debe uno considerar las posibles acciones que el usuario pueda realizar, o mejor dicho, los eventos que el programa pueda procesar, durante la ejecución del ciclo, e inhabilitar o impedir aquellos procesos que pudieran alterar la ejecución normal de la aplicación.

Espero esto sea de utilidad. Seguimos en contacto.

Al González .

Última edición por Al González fecha: 29-09-2003 a las 23:19:40.
Responder Con Cita
  #3  
Antiguo 29-09-2003
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
Completando un poco lo que te indica Al González, para lograr el efecto de pausar el ciclo y luego
continuar podrías intentar algo como esto:

Código:
var
  I: Integer;

begin
  Pausa := false;

  for I := 1 to 50000 do
  begin
    while Pausa do
      Application.ProcessMessages;

    { Aquí el proceso que realices }

    Application.ProcessMessages;
  end;
end;
Pausa sería una variable en tu formulario que inicializas a false al comienzo del ciclo for de manera
que el ciclo while no se ejecuta.

El segundo ProcessMessages permite procesar otros eventos. Uno de ellos podría ser el click de un botón
"Pausa" en donde pones la variable Pausa a true. Esto hará que la condición del ciclo while sea cierta y,
como verás, es un ciclo que no terminará mientras Pausa sea true de manera que el ciclo for queda
"suspendido".

El ProcessMessages dentro del ciclo while permitirá que se sigan procesando los mensajes, por ejemplo el
click de un botón "Continuar" en donde pondrías la variable Pausa a false haciendo que el ciclo while
termine y continúe el ciclo for.


Por otra parte, pienso que una solución "más seria" y sólida sería utilizar threads para ejecutar lo que
haces dentro del ciclo for.


// Saludos

Última edición por roman fecha: 29-09-2003 a las 04:28:07.
Responder Con Cita
  #4  
Antiguo 29-09-2003
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
Al González

Si puedes por favor edita tu mensaje para
cortar la línea de comentario dentro del código
que escribiste ya que causa que el texto de tu
comentario y los demás no quepan en la pantalla.

// Gracias


Nota posterior

Gracias Al, ahora ha quedado muy bien

Última edición por roman fecha: 30-09-2003 a las 16:43:21.
Responder Con Cita
  #5  
Antiguo 29-09-2003
Kaesbu Kaesbu is offline
Registrado
 
Registrado: sep 2003
Posts: 7
Poder: 0
Kaesbu Va por buen camino
Muchas gracias a los dos por contestar y hacerme las aclaraciones
sobre el tema. Poco a poco voy aprendiendo mas cosas sobre Delphi. Muchas gracias y un saludo.
Responder Con Cita
  #6  
Antiguo 29-09-2003
Kaesbu Kaesbu is offline
Registrado
 
Registrado: sep 2003
Posts: 7
Poder: 0
Kaesbu Va por buen camino
Uffffff, lo he probado y se me han empeorado las cosas, ya que
el bucle lo que hace es bajar un archivo. El problema es que cuando llega al application.processmessages el buffer se vacia y el programa sale del bucle. Alguna idea? Gracias.
Responder Con Cita
  #7  
Antiguo 29-09-2003
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
Para momentaneamente el programa: continuación

Cita:
Kaesbu escribió

El problema es que cuando llega al application.processmessages el buffer se vacia y el programa sale del bucle. Alguna idea? Gracias.
Habría que ver cómo estás bajando el archivo. ¿Qué es lo que haces en cada paso del bucle?

Aquí te va una idea de cómo usar threads. El ejemplo es para copiar un archivo mostrando el avance en un ProgressBar pero puede servirte como punto de partida ya que la situación es similar: copiar bloques de archivos.

Primero debes declarar un descendiente de TThread que se ocupará del copiado:

Código:
type
  TCopyFileThread = class
  private
    ProgressBar: TProgressBar; // Barra de progreso
    procedure UpdateProgress;

  protected
    procedure Execute; override;

  public
    CopyFrom: String; // Archivo origen
    CopyTo: String; // Archivo destino
    BufferSize: LongInt; // Tamaño de cada bloque
    
    constructor Create(AProgressBar: TProgressBar);
  end;
El método Execute se llama cuando se inicia el hilo y es ahí donde debes poner el código de copiado.

UpdateProgress se encargará de actualizar el ProgressBar.

La implementación es así:

Código:
constructor TCopyFile.Create(AProgressBar: TProgressBar);
begin
  // Crear el hilo pero no iniciarlo
  inherited Create(true);

  ProgressBar := AProgressBar;
  BufferSize := 255;
end;

procedure TCopyFile.UpdateProgress;
begin
  ProgressBar.StepBy(BufferSize);
end;

procedure TCopyFile.Execute;
var
  Source, Dest: TFileStream;
  Buffer: Pointer;
  BytesRead: LongInt;

begin
  Source := TFileStream.Create(CopyFrom, fmOpenRead);
  Dest := TFileStream.Create(CopyTo, fmCreate);
  GetMem(Buffer, BufferSize);
  ProgressBar.Max := Source.Size;

  try
    /*
      En este ciclo se hace el copiado

      Terminated es una variable del hilo que es false
      hasta que éste termine
    */
    while not Terminated do
    begin
      BytesRead := Source.Read(Buffer^, BufferSize);
      Dest.Write(Buffer^, BytesRead);

      /*
        Es necesario llamar a UpdateProgress mediante
        Synchronize ya que UpdateProgress usda objetos
        del VCL
      */
      Synchronize(UpdateProgress);

      if BytesRead < BufferSize then Terminate;
    end;
  finally
    Source.Free;
    Dest.Free;
    FreeMem(Buffer);
  end;
end;
Eso es todo. En tu formulario declaras una variable CopyFile de tipo TCopyFileThread. Para iniciar el copiado haces:

Código:
CopyFile := TCopyFileThread.Create(ProgressBar1);
CopyFile.CopyFrom := archivo origen;
CopyFile.CopyTo := archivo destino;
CopyFile.Resume;
donde ProgressBar1 es un ProgressBar en tu formulario.

// Saludos

En un botones adecuados de tu formulario usas los métodos

CopyFile.Suspend para pausar el copiado
CopyFile.Resume para continuar
CopyFile.Terminate para cancelar el copiado

Última edición por roman fecha: 30-09-2003 a las 16:44:01.
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


La franja horaria es GMT +2. Ahora son las 21:18:32.


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