Esperando múltiples SwingWorkers

Resuelto Vlad asked hace 12 años • 2 respuestas

Considere el siguiente fragmento de código:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;

public class TestApplet extends JApplet
{
    @Override
    public void init()
    {
        try
        {
            SwingUtilities.invokeAndWait(new Runnable()
            {
                @Override
                public void run()
                {
                    createGUI();
                }
            });
        }
        catch(InterruptedException | InvocationTargetException ex)
        {
        }
    }

    private void createGUI()
    {
        getContentPane().setLayout(new FlowLayout());
        JButton startButton = new JButton("Do work");
        startButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                JLabel label = new JLabel();
                new Worker(label).execute();
            }
        });
        getContentPane().add(startButton);
    }

    private class Worker extends SwingWorker<Void, Void>
    {
        JLabel label;

        public Worker(JLabel label)
        {
            this.label = label;
        }

        @Override
        protected Void doInBackground() throws Exception
        {
            // do work
            return null;
        }

        @Override
        protected void done()
        {
            getContentPane().remove(label);
            getContentPane().revalidate();
        }
    }
}

Aquí se agrega una etiqueta al subprograma que muestra algunos resultados intermedios del hilo de trabajo (usando métodos de publicación/proceso). Al final, la etiqueta se elimina del panel del subprograma. Mi pregunta es, ¿cómo podría crear varias etiquetas, cada una con su propio hilo de trabajo, y eliminarlas cuando hayan terminado?

Gracias de antemano.

ACTUALIZAR:

Espero que esto aclare mi pregunta. Me gustaría que las etiquetas se quitaran todas a la vez, cuando todos los trabajadores hayan terminado sus tareas, no inmediatamente después de que cada trabajador haya terminado.

ACTUALIZACIÓN 2:

El siguiente código parece estar haciendo lo que necesito. Por favor comente si lo hice de la manera correcta. Tengo la sensación de que algo anda mal. Un problema es que las etiquetas a la derecha del botón permanecen visibles aunque se eliminen. setVisible(false) parece resolver este problema. ¿Es esa la manera de hacerlo?

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;

public class TestApplet extends JApplet
{
    private Queue<JLabel> labels = new LinkedList<>();
    private static final Random rand = new Random();

    @Override
    public void init()
    {
        try
        {
            SwingUtilities.invokeAndWait(new Runnable()
            {
                @Override
                public void run()
                {
                    createGUI();
                }
            });
        }
        catch(InterruptedException | InvocationTargetException ex){}
    }

    private void createGUI()
    {
        getContentPane().setLayout(new FlowLayout());
        JButton startButton = new JButton("Do work");
        startButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                ExecutorService executor = Executors.newFixedThreadPool(10);
                for(int i = 0; i < 10; i++)
                {
                    JLabel label = new JLabel();
                    getContentPane().add(label);
                    executor.execute(new Counter(label));
                }
            }
        });
        getContentPane().add(startButton);
    }

    private class Counter extends SwingWorker<Void, Integer>
    {
        private JLabel label;

        public Counter(JLabel label)
        {
            this.label = label;
        }

        @Override
        protected Void doInBackground() throws Exception
        {
            for(int i = 1; i <= 100; i++)
            {
                publish(i);
                Thread.sleep(rand.nextInt(80));
            }

            return null;
        }

        @Override
        protected void process(List<Integer> values)
        {
            label.setText(values.get(values.size() - 1).toString());
        }

        @Override
        protected void done()
        {
            labels.add(label);

            if(labels.size() == 10)
            {
                while(!labels.isEmpty())
                    getContentPane().remove(labels.poll());

                getContentPane().revalidate();
            }
        }
    }
}
Vlad avatar Jul 06 '12 23:07 Vlad
Aceptado

El código que tienes ya lo hace hasta cierto punto. En realidad, debe agregar la etiqueta al panel de contenido cuando se hace clic en el botón. Algo como esto:

 JLabel label = new JLabel();
 getContentPane().add(label);
 getContentPane().validate();
 new Worker(label).execute();

Puede ser una buena idea poner algo de texto en la etiqueta para que realmente lo veas cuando se agregue a la pantalla.

 JLabel label = new JLabel("Hello...I am here");

Y finalmente, en el método doInBackground() puedes agregar código para actualizar la etiqueta mientras se ejecuta alguna tarea:

 for(int i = 0;i < 100; i++){
            Thread.sleep(20);
            label.setText("Counting..." + i);
  }

De esta manera verás la tarea ejecutándose. Si hace clic en el botón varias veces, verá varias etiquetas y cada una de ellas desaparecerá una vez completada la tarea.

Vincent Ramdhanie avatar Jul 06 '2012 17:07 Vincent Ramdhanie