Java/JDK 6/Swing Worker

Материал из Java эксперт
Перейти к: навигация, поиск

Swing Worker from JDK 6 SE

   <source lang="java">

import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; public class SwingWorkerDemo {

 public static void main(String[] args) {
   JTextArea textArea = new JTextArea(10, 20);
   final JProgressBar progressBar = new JProgressBar(0, 10);
   final CounterTask task = new CounterTask();
   task.addPropertyChangeListener(new PropertyChangeListener() {
     public void propertyChange(PropertyChangeEvent evt) {
       if ("progress".equals(evt.getPropertyName())) {
         progressBar.setValue((Integer) evt.getNewValue());
       }
     }
   });
   JButton startButton = new JButton("Start");
   startButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       task.execute();
     }
   });
   JButton cancelButton = new JButton("Cancel");
   cancelButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       task.cancel(true);
     }
   });
   JPanel buttonPanel = new JPanel();
   buttonPanel.add(startButton);
   buttonPanel.add(cancelButton);
   JPanel cp = new JPanel();
   LayoutManager layout = new BoxLayout(cp, BoxLayout.Y_AXIS);
   cp.setLayout(layout);
   cp.add(buttonPanel);
   cp.add(new JScrollPane(textArea));
   cp.add(progressBar);
   JFrame frame = new JFrame("SwingWorker Demo");
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.setContentPane(cp);
   frame.pack();
   frame.setVisible(true);
 }

} class CounterTask extends SwingWorker<Integer, Integer> {

 private static final int DELAY = 1000;
 public CounterTask() {
 }
 @Override
 protected Integer doInBackground() throws Exception {
   int i = 0;
   int count = 10;
   while (!isCancelled() && i < count) {
     i++;
     publish(new Integer[] { i });
     setProgress(count * i / count);
     Thread.sleep(DELAY);
   }
   return count;
 }
  
 protected void process(List<Integer> chunks) {
   for (int i : chunks)
     System.out.println(i);
 }
 @Override
 protected void done() {
   if (isCancelled())
     System.out.println("Cancelled !");
   else
     System.out.println("Done !");
 }

}

       </source>
   
  
 
  



Swing worker from org.jdesktop.swingworker

   <source lang="java">

/*

* $Id: AccumulativeRunnable.java,v 1.2 2006/09/28 20:20:28 idk Exp $
* 
* Copyright ?2005 Sun Microsystems, Inc. All rights
* reserved. Use is subject to license terms.
*/

package org.jdesktop.swingworker; import java.util.*; import javax.swing.SwingUtilities; /**

* An abstract class to be used in the cases where we need {@code Runnable}
* to perform  some actions on an appendable set of data.
* The set of data might be appended after the {@code Runnable} is
* sent for the execution. Usually such {@code Runnables} are sent to
* the EDT.
*
*

* Usage example: * * <p> * Say we want to implement JLabel.setText(String text) which sends * {@code text} string to the JLabel.setTextImpl(String text) on the EDT. * In the event JLabel.setText is called rapidly many times off the EDT * we will get many updates on the EDT but only the last one is important. * (Every next updates overrides the previous one.) * We might want to implement this {@code setText} in a way that only * the last update is delivered. * <p> * Here is how one can do this using {@code AccumulativeRunnable}: *

 * AccumulativeRunnable<String> doSetTextImpl = 
 * new  AccumulativeRunnable<String>() {
 *     @Override 
 *     protected void run(List<String> args) {
 *         //set to the last string being passed
 *         setTextImpl(args.get(args.size() - 1);
 *     }
 * }
 * void setText(String text) {
 *     //add text and send for the execution if needed.
 *     doSetTextImpl.add(text);
 * }
 * 
*
* <p>
* Say we want want to implement addDirtyRegion(Rectangle rect)
* which sends this region to the 
* handleDirtyRegions(List<Rect> regions) on the EDT.
* addDirtyRegions better be accumulated before handling on the EDT.
* 
* <p>
* Here is how it can be implemented using AccumulativeRunnable:
*
 * AccumulativeRunnable<Rectangle> doHandleDirtyRegions = 
 *     new AccumulativeRunnable<Rectangle>() {
 *         @Override 
 *         protected void run(List<Rectangle> args) {
 *             handleDirtyRegions(args);
 *         }
 *     };
 *  void addDirtyRegion(Rectangle rect) {
 *      doHandleDirtyRegions.add(rect);
 *  }
 * 
*
* @author Igor Kushnirskiy
* @version $Revision: 1.2 $ $Date: 2006/09/28 20:20:28 $
*
* @param <T> the type this {@code Runnable} accumulates
* 
*/

abstract class AccumulativeRunnable<T> implements Runnable {

   private List<T> arguments = null;
   
   /**
    * Equivalent to {@code Runnable.run} method with the
    * accumulated arguments to process.
    *
    * @param args accumulated arguments to process.
    */
   protected abstract void run(List<T> args);
   
   /**
    * {@inheritDoc}
    *
    * <p>
    * This implementation calls {@code run(List<T> args)} method
    * with the list of accumulated arguments.
    */
   public final void run() {
       run(flush());
   }
   
   /**
    * appends arguments and sends this {@code Runnable} for the
    * execution if needed.
    * <p>
    * This implementation uses {@see #submit} to send this 
    * {@code Runnable} for execution. 
    * @param args the arguments to accumulate
    */
   public final synchronized void add(T... args) {
       boolean isSubmitted = true;
       if (arguments == null) {
           isSubmitted = false;
           arguments = new ArrayList<T>();
       }
       Collections.addAll(arguments, args);
       if (!isSubmitted) {
           submit();
       }
   }
   /**
    * Sends this {@code Runnable} for the execution
    *
    * <p>
    * This method is to be executed only from {@code add} method.
    *
    * <p>
    * This implementation uses {@code SwingWorker.invokeLater}.
    */
   protected void submit() {
       SwingUtilities.invokeLater(this);
   }
       
   /**
    * Returns accumulated arguments and flashes the arguments storage.
    *
    * @return accumulated arguments
    */
   private final synchronized List<T> flush() {
       List<T> list = arguments;
       arguments = null;
       return list;
   }

} /////////////////////////////////////////////////////////// /*

* $Id: SwingPropertyChangeSupport.java,v 1.1 2005/06/18 21:27:14 idk Exp $
* 
* Copyright ?2005 Sun Microsystems, Inc. All rights
* reserved. Use is subject to license terms.
*/

package org.jdesktop.swingworker; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeEvent; import javax.swing.SwingUtilities; /**

* This subclass of {@code java.beans.PropertyChangeSupport} is almost
* identical in functionality. The only difference is if constructed with 
* {@code SwingPropertyChangeSupport(sourceBean, true)} it ensures
* listeners are only ever notified on the Event Dispatch Thread.
*
* @author Igor Kushnirskiy
* @version $Revision: 1.1 $ $Date: 2005/06/18 21:27:14 $
*/

public final class SwingPropertyChangeSupport extends PropertyChangeSupport {

   /**
    * Constructs a SwingPropertyChangeSupport object.
    *
    * @param sourceBean  The bean to be given as the source for any
    *        events.
    * @throws NullPointerException if {@code sourceBean} is 
    *         {@code null}
    */
   public SwingPropertyChangeSupport(Object sourceBean) {
       this(sourceBean, false);
   }
   /**
    * Constructs a SwingPropertyChangeSupport object.
    * 
    * @param sourceBean the bean to be given as the source for any events
    * @param notifyOnEDT whether to notify listeners on the Event
    *        Dispatch Thread only
    *
    * @throws NullPointerException if {@code sourceBean} is 
    *         {@code null}
    * @since 1.6
    */
   public SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT) {
       super(sourceBean);
       this.notifyOnEDT = notifyOnEDT;
   }
   /**
    * {@inheritDoc}
    *
    * <p>
    * If {@see #isNotifyOnEDT} is {@code true} and called off the
    * Event Dispatch Thread this implementation uses 
    * {@code SwingUtilities.invokeLater} to send out the notification
    * on the Event Dispatch Thread. This ensures  listeners
    * are only ever notified on the Event Dispatch Thread.
    *
    * @throws NullPointerException if {@code evt} is 
    *         {@code null}
    * @since 1.6
    */
   public void firePropertyChange(final PropertyChangeEvent evt) {
       if (evt == null) {
           throw new NullPointerException();
       }
       if (! isNotifyOnEDT()
           || SwingUtilities.isEventDispatchThread()) {
           super.firePropertyChange(evt);
       } else {
           SwingUtilities.invokeLater(
               new Runnable() {
                   public void run() {
                       firePropertyChange(evt);
                   }
               });
       }
   }
   /**
    * Returns {@code notifyOnEDT} property.
    * 
    * @return {@code notifyOnEDT} property
    * @see #SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT)
    * @since 1.6
    */
   public final boolean isNotifyOnEDT() {
       return notifyOnEDT;
   }
   // Serialization version ID
   static final long serialVersionUID = 7162625831330845068L;
   /**
    * whether to notify listeners on EDT
    * 
    * @serial 
    * @since 1.6
    */ 
   private final boolean notifyOnEDT;

}

/////////////////////////////////////////////////////////// /*

* $Id: SwingWorker.java,v 1.5 2007/03/01 19:55:54 idk Exp $
* 
* Copyright ?2005 Sun Microsystems, Inc. All rights
* reserved. Use is subject to license terms.
*/

package org.jdesktop.swingworker; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeEvent; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.*; import java.awt.event.*; import javax.swing.SwingUtilities; import javax.swing.Timer; /**

* An abstract class to perform lengthy GUI-interacting tasks in a
* dedicated thread.
* 
* <p>
* When writing a multi-threaded application using Swing, there are
* two constraints to keep in mind:
* (refer to 
* 


Swing Worker Image Loader

   <source lang="java">

import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.List; import java.util.ArrayList; import java.io.File; import java.io.IOException; import java.awt.Image; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.imageio.ImageIO; import org.jdesktop.swingworker.SwingWorker; public class ImageLoader extends JFrame {

   private JTextArea log;
   private JPanel viewer;
   
   public ImageLoader() {
       super("Image Loader");
       
       this.log = new JTextArea(4, 4);
       this.viewer = new JPanel();
       
       JButton start = new JButton("Start");
       start.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              String[] files = new String[] {
                  "Bodie_small.png", "Carmela_small.png",
                  "Death Valley_small.png", "Lake_small.png"
              };
              new ImageLoadingWorker(log, viewer, files).execute();
          }
       });
       
       add(new JScrollPane(log), BorderLayout.NORTH);
       add(new JScrollPane(viewer), BorderLayout.CENTER);
       add(start, BorderLayout.SOUTH);
       
       setSize(360, 280);
   }
   
   public static void main(String... args) {
       SwingUtilities.invokeLater(new Runnable() {
           public void run() {
               new ImageLoader().setVisible(true);
           }
       });
   }

}

// Final result is a list of Image // Intermediate result is a message as a String class ImageLoadingWorker extends SwingWorker<List<Image>, String> {

 private JTextArea log;
 private JPanel viewer;
 private String[] filenames;
 public ImageLoadingWorker(JTextArea log, JPanel viewer, String... filenames) {
   this.log = log;
   this.viewer = viewer;
   this.filenames = filenames;
 }
 // In the EDT
 @Override
 protected void done() {
   try {
     for (Image image : get()) {
       viewer.add(new JLabel(new ImageIcon(image)));
       viewer.revalidate();
     }
   } catch (Exception e) { }
 }
 // In the EDT
 @Override
 protected void process(String... messages) {
   for (String message : messages) {
     log.append(message);
     log.append("\n");
   }
 }
 // In a thread
 @Override
 public List<Image> doInBackground() {
   List<Image> images = new ArrayList<Image>();
   for (String filename : filenames) {
     try {
       images.add(ImageIO.read(new File("./build/"+filename)));
       publish("Loaded " + filename);
     } catch (IOException ioe) {
       publish("Error loading " + filename);
     }
   }
   return images;
 }  

}


      </source>