17 julio 2009

El componente BackwroundWorker (y 2)

Vamos a ver un ejemplo de cómo utilizar este componente con un hilo de ejecución que recorra todos los números del 1 al 100 y nos calcule los múltiplos de 5, 7 y 9. Este sería el formulario principal de nuestro proyecto:


El formulario se compone de los siguientes componentes:

- 2 botones de la clase TButton llamados BComenzar y BCancelar para iniciar o detener el hilo de ejecución.

- 1 componente TBackgroundWorker llamado BackgroundWorker.

- 1 barra de progreso de la clase TProgressBar llamada Progreso y con su propiedad Smooth a True.

- 3 etiquetas (TLabel) y 3 casillas (TEdit) llamadas Multiplos5, Multiplos7 y Multiplos9 donde se irán alojando los múltiplos encontrados de cada uno.

- 1 barra de estado de la clase TStatusBar llamada Estado con su propiedad SimplePanel a True.

Comencemos a meter código:

1º Al pulsar el botón Comenzar ponemos en marcha el hilo:

procedure TForm1.BComenzarClick(Sender: TObject);
begin
BackgroundWorker.Execute;
end;

2º Al pulsar el botón Cancelar le pedimos al hilo que se detenga:

procedure TForm1.BDetenerClick(Sender: TObject);
begin
BackgroundWorker.Cancel;
end;

3º En el evento OnWork del componente BackgroundWorker recorremos los 100 números:

procedure TForm1.BackgroundWorkerWork(Worker: TBackgroundWorker);
var
i: Integer;
begin
for i := 1 to 100 do
begin
// ¿Hay que cancelar el proceso?
if Worker.CancellationPending then
begin
// Le indicamos al hilo que lo cancelamos
Worker.AcceptCancellation;
Exit;
end;

// ¿Es múltiplo de 5?
if i mod 5 = 0 then
Worker.ReportFeedback(5, i);

// ¿Es múltiplo de 7?
if i mod 7 = 0 then
Worker.ReportFeedback(7, i);

// ¿Es múltiplo de 9?
if i mod 9 = 0 then
Worker.ReportFeedback(9, i);

// Esperamos 50 milisegundos
Sleep(50);

// Incrementamos la barra de progreso
Worker.ReportProgress(i);
end;
end;

Al principio del bucle controlamos si nos piden abandonar el hilo de ejecución:

// ¿Hay que cancelar el proceso?
if Worker.CancellationPending then
begin
// Le indicamos al hilo que lo cancelamos
Worker.AcceptCancellation;
Exit;
end;

Después comprobamos los múltiplos de cada número y en el caso de que así sea envío provoco un evento OnWorkFeedBack para notificar el número que he encontrado:

// ¿Es múltiplo de 5?
if i mod 5 = 0 then
Worker.ReportFeedback(5, i);

// ¿Es múltiplo de 7?
if i mod 7 = 0 then
Worker.ReportFeedback(7, i);

// ¿Es múltiplo de 9?
if i mod 9 = 0 then
Worker.ReportFeedback(9, i);

Y por último provoco un pequeño retardo de 50 milisegundos (para ir viendo el progreso) y provoco un evento OnWorkProgress para notificar el incremento en la barra de progreso:

// Esperamos 50 milisegundos
Sleep(50);

// Incrementamos la barra de progreso
Worker.ReportProgress(i);

Sigamos...

4º En el evento OnWorkFeedBack recogemos el mensaje que nos manda el hilo para ir guardando en cada casilla los múltiplos de cada número:

procedure TForm1.BackgroundWorkerWorkFeedback(Worker: TBackgroundWorker;
FeedbackID, FeedbackValue: Integer);
begin
case FeedbackID of
5: Multiplos5.Text := Multiplos5.Text + IntToStr(FeedbackValue) + ',';
7: Multiplos7.Text := Multiplos7.Text + IntToStr(FeedbackValue) + ',';
9: Multiplos9.Text := Multiplos9.Text + IntToStr(FeedbackValue) + ',';
end;
end;

5º En el evento OnWorkProgress actualizamos la barra de progreso y la barra de estado en pantalla:

procedure TForm1.BackgroundWorkerWorkProgress(Worker: TBackgroundWorker;
PercentDone: Integer);
begin
Progreso.Position := PercentDone;
Estado.SimpleText := 'Procesando... ' + IntToStr(PercentDone) + '%';
end;

6º En el evento OnWorkComplete le decimos al usuario en la barra de progreso que hemos terminado:

procedure TForm1.BackgroundWorkerWorkComplete(Worker: TBackgroundWorker;
Cancelled: Boolean);
begin
Estado.SimpleText := 'Proceso finalizado';
end;

7º Por si acaso al usuario le da por cerrar el formulario mientras está el hilo en marcha tenemos que cancelarlo y esperar a que termine (al igual que hacen los programas como Emule o BitTorrent cuando lo cerramos y espera a liberar memoria y cerrar las conexiones):

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// ¿Esta el hilo en marcha?
if BackgroundWorker.IsWorking then
begin
// Le indicamos que se detenga
BackgroundWorker.Cancel;
// Esperamos a que se detenga
BackgroundWorker.WaitFor;
end;
end;

Al ejecutar el programa irá rellenando las casillas correspondientes:


Hasta finalizar el proceso:


Como podemos apreciar, este componente nos facilita mucho la labor con los hilos de ejecución respecto a la clase TThread. Por las pruebas que he realizado en otros programas más complejos (facturación) es bastante sencillo de manejar y muy estable.

Pruebas realizadas en RAD Studio 2007.

3 comentarios:

Anónimo dijo...

Enhorabuena por tu blog, si quieres puedes apuntarte al directorio web/blog www.cincolinks.com podrás promocionar tu web, con tu ficha y tus votaciones y valoraciones, con un método de intercambio de visitas llamado 5links! con el que tu blog será visitado tanto como visites a los demás y que harán que tu blog se de a conocer por toda la red. Pásate ;)

Creo que no hay muchos blogs de las características y temática del tuyo en este directorio, me gustaría mucho que participaras.


Saludos, espero verte por www.cincolinks.com.

Administrador dijo...

La última vez que vendí enlaces externos me bajó Google el PageRank de este blog de 3 a 0.

Vivan los monopolios!!!

sachos345 dijo...

Hola como te va.Tengo un problemba.Hago todo como decis pero cuadno apreto el boton comenzar la barra se carga instantaneamente y los multiplosn o me los muestra.Porque es??Ayuda!

Publicidad