2012-07-06 144 views
10

請考慮下面的代碼片斷:等待多個SwingWorkers

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(); 
     } 
    } 
} 

下面是添加標籤到顯示工作線程的一些中間結果的小應用程序(使用發佈/處理方法)。最後,標籤將從applet的窗格中移除。我的問題是,我如何創建多個標籤,每個標籤都有自己的工作線程,並在完成所有標籤時將其刪除?

在此先感謝。

UPDATE:

我希望這將澄清我的問題。我希望當所有員工都完成任務時,一次性刪除所有標籤,而不是在每名員工完成任務後立即刪除標籤。

更新2:

下面的代碼似乎是在做什麼,我需要。請評論我是否以正確的方式做到了這一點。我有一種感覺是錯的。一個問題是,儘管按鈕右側的標籤被刪除,但仍然可見。 setVisible(false)似乎解決了這個問題。這是做到這一點的方式嗎?

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(); 
      } 
     } 
    } 
} 
+0

你也可以考慮把它們放在一個列表('JList')。 – 2012-07-06 17:14:59

+0

@AndrewThompson,是的,但我應該在哪裏放置等待它們的代碼?它應該是另一個SwingWorker產卵其他幾個? – Vlad 2012-07-06 17:46:14

+0

請不要吞下例外。 – trashgod 2012-07-07 01:41:29

回答

14

我打算在所有工作人員完成任務時一併刪除所有標籤。

如描述的hereCountDownLatch在這種情況下效果良好。在下面的示例中,每個工人在完成時調用latch.countDown(),工人在latch.await()上阻塞,直到完成所有任務。出於演示目的,Supervisor更新標籤。評論中顯示的批發清除在技術上是可行的,但通常不具吸引力。相反,請考慮JListJTable

Worker Latch Test

import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Queue; 
import java.util.Random; 
import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import javax.swing.*; 

/** 
* @see https://stackoverflow.com/a/11372932/230513 
* @see https://stackoverflow.com/a/3588523/230513 
*/ 
public class WorkerLatchTest extends JApplet { 

    private static final int N = 8; 
    private static final Random rand = new Random(); 
    private Queue<JLabel> labels = new LinkedList<JLabel>(); 
    private JPanel panel = new JPanel(new GridLayout(0, 1)); 
    private JButton startButton = new JButton(new StartAction("Do work")); 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       frame.setTitle("Test"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new WorkerLatchTest().createGUI()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    @Override 
    public void init() { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       add(new WorkerLatchTest().createGUI()); 
      } 
     }); 
    } 

    private JPanel createGUI() { 
     for (int i = 0; i < N; i++) { 
      JLabel label = new JLabel("0", JLabel.CENTER); 
      label.setOpaque(true); 
      panel.add(label); 
      labels.add(label); 
     } 
     panel.add(startButton); 
     return panel; 
    } 

    private class StartAction extends AbstractAction { 

     private StartAction(String name) { 
      super(name); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
       startButton.setEnabled(false); 
       CountDownLatch latch = new CountDownLatch(N); 
       ExecutorService executor = Executors.newFixedThreadPool(N); 
       for (JLabel label : labels) { 
        label.setBackground(Color.white); 
        executor.execute(new Counter(label, latch)); 
       } 
       new Supervisor(latch).execute(); 
     } 
    } 

    private class Supervisor extends SwingWorker<Void, Void> { 

     CountDownLatch latch; 

     public Supervisor(CountDownLatch latch) { 
      this.latch = latch; 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      latch.await(); 
      return null; 
     } 

     @Override 
     protected void done() { 
      for (JLabel label : labels) { 
       label.setText("Fin!"); 
       label.setBackground(Color.lightGray); 
      } 
      startButton.setEnabled(true); 
      //panel.removeAll(); panel.revalidate(); panel.repaint(); 
     } 
    } 

    private static class Counter extends SwingWorker<Void, Integer> { 

     private JLabel label; 
     CountDownLatch latch; 

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

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

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

     @Override 
     protected void done() { 
      label.setBackground(Color.green); 
      latch.countDown(); 
     } 
    } 
} 
+0

很好的例子,很好的 – mKorbel 2012-07-07 07:24:17

+0

非常感謝! – Vlad 2012-07-07 07:44:18

+1

不客氣,像這樣[https://sites.google.com/site/drjohnbmatthews/subway]中顯示的,使用[tag:java-web-start]提供各種部署選項的混合applet /應用程序。 – trashgod 2012-07-07 07:53:59

1

您擁有的代碼已經在一定程度上做到了這一點。當點擊按鈕時,您需要實際將標籤添加到內容窗格。事情是這樣的:

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

它可能是一個好主意,把一些文字的標籤,所以你真正看到它時,它被添加到屏幕上。

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

終於在doInBackground()方法,你可以添加一些代碼來更新標籤的一些任務運行:

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

這樣,你實際看到任務的運行。如果多次單擊該按鈕,則會看到多個標籤,並且在任務完成後它們都會消失。

+0

感謝您的快速回復。在粘貼之前,我簡化了代碼。該標籤確實有一些文本並被添加到內容窗格中。 :)感謝您的建議,但。我想我沒有清楚地陳述我的問題。我打算在所有工作人員都完成任務時將所有標籤刪除 – Vlad 2012-07-06 17:36:53