2012-07-06 34 views
10

Hãy xem xét các đoạn mã sau:chờ nhiều 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(); 
     } 
    } 
} 

Dưới đây là thêm một nhãn để applet hiển thị một số kết quả trung gian của các chủ đề lao động (sử dụng xuất bản/phương pháp xử lý). Cuối cùng, nhãn được lấy ra khỏi ngăn của applet. Câu hỏi của tôi là, làm cách nào tôi có thể tạo một số nhãn, mỗi nhãn có chuỗi Công việc riêng và xóa chúng khi tất cả được thực hiện?

Xin cảm ơn trước.

UPDATE:

Tôi hy vọng điều này sẽ làm rõ câu hỏi của tôi. Tôi muốn các nhãn được gỡ bỏ tất cả cùng một lúc, khi tất cả các công nhân đã hoàn thành nhiệm vụ của họ, không phải ngay lập tức sau khi mỗi công nhân đã hoàn thành.

UPDATE 2:

Các mã sau đây có vẻ là làm những gì tôi cần. Hãy bình luận xem tôi đã làm đúng cách chưa. Tôi có cảm giác có điều gì đó sai trái. Một vấn đề là các nhãn ở bên phải của nút vẫn có thể nhìn thấy mặc dù chúng được gỡ bỏ. setVisible (false) dường như giải quyết vấn đề này. Đó có phải là cách để làm điều đó không?

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

Bạn cũng có thể xem xét đặt chúng trong một danh sách ('JList'). –

+0

@AndrewThompson, Vâng, nhưng tôi nên đặt mã sẽ chờ ở đâu? Liệu nó có phải là một SwingWorker sinh sản khác không? – Vlad

+0

Xin đừng nuốt các ngoại lệ. – trashgod

Trả lời

14

Tôi định loại bỏ tất cả các nhãn với nhau khi tất cả công nhân đã hoàn thành nhiệm vụ của mình.

Như được mô tả here, CountDownLatch hoạt động tốt trong ngữ cảnh này. Trong ví dụ bên dưới, mỗi nhân viên gọi latch.countDown() khi hoàn thành và một khối công nhân Supervisor trên latch.await() cho đến khi tất cả các tác vụ hoàn tất. Đối với mục đích trình diễn, các Supervisor cập nhật các nhãn. Bán buôn loại bỏ, thể hiện trong ý kiến, là kỹ thuật có thể nhưng thường không hấp dẫn. Thay vào đó, hãy xem xét JList hoặc JTable.

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

ví dụ tuyệt vời, tốt nhất – mKorbel

+0

Cảm ơn bạn rất nhiều! – Vlad

+1

Bạn được chào đón; một applet/ứng dụng lai như thế này cung cấp nhiều tùy chọn triển khai khác nhau bằng cách sử dụng [tag: java-web-start], như được hiển thị [ở đây] (https://sites.google.com/site/drjohnbmatthews/subway). – trashgod

1

Mã bạn đã làm ở một mức độ nhất định. Bạn cần phải thêm nhãn vào contentpane khi nút được nhấp. Một cái gì đó như thế này:

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

Có thể nên đặt một số văn bản trong nhãn để bạn thực sự thấy nó khi được thêm vào màn hình.

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

Và cuối cùng trong phương pháp doInBackground(), bạn có thể thêm một số mã để cập nhật các nhãn như một số nhiệm vụ đang chạy:

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

Bằng cách này bạn thực sự thấy nhiệm vụ đang chạy. Nếu bạn nhấp vào nút nhiều lần, bạn sẽ thấy nhiều nhãn và mỗi nhãn biến mất sau khi tác vụ hoàn tất.

+0

Cảm ơn bạn đã trả lời nhanh. Tôi đã đơn giản hóa mã trước khi dán vào đây. Nhãn thực sự có một số văn bản và được thêm vào ngăn nội dung. :) Cảm ơn lời đề nghị mặc dù. Tôi nghĩ rằng tôi đã không nêu rõ câu hỏi của tôi. Những gì tôi có ý định là để loại bỏ tất cả các nhãn với nhau khi tất cả các công nhân của họ đã hoàn thành nhiệm vụ – Vlad