Java/Swing JFC/SwingWorker

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

3rd version of SwingWorker

   <source lang="java">
  

//revised from arsenal import javax.swing.SwingUtilities; /**

* This is the 3rd version of SwingWorker (also known as
* SwingWorker 3), an abstract class that you subclass to
* perform GUI-related work in a dedicated thread.  For
* instructions on and examples of using this class, see:
* 
* http://java.sun.ru/docs/books/tutorial/uiswing/misc/threads.html
*
* Note that the API changed slightly in the 3rd version:
* You must now invoke start() on the SwingWorker after
* creating it.
*/

public abstract class SwingWorker {

   private Object value;  // see getValue(), setValue()
   /** 
    * Class to maintain reference to current worker thread
    * under separate synchronization control.
    */
   private static class ThreadVar {
       private Thread thread;
       ThreadVar(Thread t) { thread = t; }
       synchronized Thread get() { return thread; }
       synchronized void clear() { thread = null; }
   }
   private ThreadVar threadVar;
   /** 
    * Get the value produced by the worker thread, or null if it 
    * hasn"t been constructed yet.
    */
   protected synchronized Object getValue() { 
       return value; 
   }
   /** 
    * Set the value produced by worker thread 
    */
   private synchronized void setValue(Object x) { 
       value = x; 
   }
   /** 
    * Compute the value to be returned by the get method. 
    */
   public abstract Object construct();
   /**
    * Called on the event dispatching thread (not on the worker thread)
    * after the construct method has returned.
    */
   public void finished() {
   }
   /**
    * A new method that interrupts the worker thread.  Call this method
    * to force the worker to stop what it"s doing.
    */
   public void interrupt() {
       Thread t = threadVar.get();
       if (t != null) {
           t.interrupt();
       }
       threadVar.clear();
   }
   /**
    * Return the value created by the construct method.  
    * Returns null if either the constructing thread or the current
    * thread was interrupted before a value was produced.
    * 
    * @return the value created by the construct method
    */
   public Object get() {
       while (true) {  
           Thread t = threadVar.get();
           if (t == null) {
               return getValue();
           }
           try {
               t.join();
           }
           catch (InterruptedException e) {
               Thread.currentThread().interrupt(); // propagate
               return null;
           }
       }
   }
   /**
    * Start a thread that will call the construct method
    * and then exit.
    */
   public SwingWorker() {
       final Runnable doFinished = new Runnable() {
          public void run() { finished(); }
       };
       Runnable doConstruct = new Runnable() { 
           public void run() {
               try {
                   setValue(construct());
               }
               finally {
                   threadVar.clear();
               }
               SwingUtilities.invokeLater(doFinished);
           }
       };
       Thread t = new Thread(doConstruct);
       threadVar = new ThreadVar(t);
   }
   /**
    * Start the worker thread.
    */
   public void start() {
       Thread t = threadVar.get();
       if (t != null) {
           t.start();
       }
   }

}


 </source>
   
  
 
  



A pool of work threads

   <source lang="java">
  

/*

* WorkThreadPool.java - Background thread pool that does stuff
* :tabSize=8:indentSize=8:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 2000 Slava Pestov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

//{{{ Imports import java.util.EventListener; import javax.swing.SwingUtilities; import javax.swing.event.EventListenerList; //}}} /**

* A pool of work threads.
* 
* @author Slava Pestov
* @version $Id: WorkThreadPool.java 12504 2008-04-22 23:12:43Z ezust $
* @see org.gjt.sp.util.WorkThread
* @since jEdit 2.6pre1
*/

public class WorkThreadPool {

 // {{{ WorkThreadPool constructor
 /**
  * Creates a new work thread pool with the specified number of work threads.
  * 
  * @param name
  *          The thread name prefix
  * @param count
  *          The number of work threads
  */
 public WorkThreadPool(String name, int count) {
   listenerList = new EventListenerList();
   if (count != 0) {
     threadGroup = new ThreadGroup(name);
     threads = new WorkThread[count];
     for (int i = 0; i < threads.length; i++) {
       threads[i] = new WorkThread(this, threadGroup, name + " #" + (i + 1));
     }
   }
 } // }}}
 // {{{ start() method
 /**
  * Starts all the threads in this thread pool.
  */
 public void start() {
   /* not really needed since threads don"t start until after */
   synchronized (lock) {
     started = true;
     if (awtRequestCount != 0 && requestCount == 0)
       queueAWTRunner();
   }
   if (threads != null) {
     for (int i = 0; i < threads.length; i++) {
       threads[i].start();
     }
   }
 } // }}}
 // {{{ addWorkRequest() method
 /**
  * Adds a work request to the queue.
  * 
  * @param run
  *          The runnable
  * @param inAWT
  *          If true, will be executed in AWT thread. Otherwise, will be
  *          executed in work thread
  */
 public void addWorkRequest(Runnable run, boolean inAWT) {
   if (threads == null) {
     run.run();
     return;
   }
   synchronized (lock) {
     // {{{ if there are no requests, execute AWT requests immediately
     if (started && inAWT && requestCount == 0 && awtRequestCount == 0) {
       // Log.log(Log.DEBUG,this,"AWT immediate: " + run);
       if (SwingUtilities.isEventDispatchThread())
         run.run();
       else
         SwingUtilities.invokeLater(run);
       return;
     } // }}}
     Request request = new Request(run);
     // {{{ Add to AWT queue...
     if (inAWT) {
       if (firstAWTRequest == null && lastAWTRequest == null)
         firstAWTRequest = lastAWTRequest = request;
       else {
         lastAWTRequest.next = request;
         lastAWTRequest = request;
       }
       awtRequestCount++;
       // if no requests are running, requestDone()
       // will not be called, so we must queue the
       // AWT runner ourselves.
       if (started && requestCount == 0)
         queueAWTRunner();
     } // }}}
     // {{{ Add to work thread queue...
     else {
       if (firstRequest == null && lastRequest == null)
         firstRequest = lastRequest = request;
       else {
         lastRequest.next = request;
         lastRequest = request;
       }
       requestCount++;
     } // }}}
     lock.notifyAll();
   }
 } // }}}
 // {{{ waitForRequests() method
 /**
  * Waits until all requests are complete.
  */
 public void waitForRequests() {
   if (threads == null)
     return;
   synchronized (waitForAllLock) {
     while (requestCount != 0) {
       try {
         waitForAllLock.wait();
       } catch (InterruptedException ie) {
       }
     }
   }
   if (SwingUtilities.isEventDispatchThread()) {
     // do any queued AWT runnables
     doAWTRequests();
   } else {
     try {
       SwingUtilities.invokeAndWait(new RunRequestsInAWTThread());
     } catch (Exception e) {
     }
   }
 } // }}}
 // {{{ getRequestCount() method
 /**
  * Returns the number of pending requests.
  * 
  * @return the pending request count
  */
 public int getRequestCount() {
   return requestCount;
 } // }}}
 // {{{ getThreadCount() method
 /**
  * Returns the number of threads in this pool.
  * 
  * @return the thread count
  */
 public int getThreadCount() {
   if (threads == null)
     return 0;
   else
     return threads.length;
 } // }}}
 // {{{ getThread() method
 /**
  * Returns the specified thread.
  * 
  * @param index
  *          The index of the thread
  * @return a WorkThread
  */
 public WorkThread getThread(int index) {
   return threads[index];
 } // }}}
 // {{{ addProgressListener() method
 /**
  * Adds a progress listener to this thread pool.
  * 
  * @param listener
  *          The listener
  */
 public void addProgressListener(WorkThreadProgressListener listener) {
   listenerList.add(WorkThreadProgressListener.class, listener);
 } // }}}
 // {{{ removeProgressListener() method
 /**
  * Removes a progress listener from this thread pool.
  * 
  * @param listener
  *          The listener
  */
 public void removeProgressListener(WorkThreadProgressListener listener) {
   listenerList.remove(WorkThreadProgressListener.class, listener);
 } // }}}
 // {{{ Package-private members
 final Object lock = new Object();
 final Object waitForAllLock = new Object();
 // {{{ fireStatusChanged() method
 void fireStatusChanged(WorkThread thread) {
   final Object[] listeners = listenerList.getListenerList();
   if (listeners.length != 0) {
     int index = 0;
     for (int i = 0; i < threads.length; i++) {
       if (threads[i] == thread) {
         index = i;
         break;
       }
     }
     for (int i = listeners.length - 2; i >= 0; i--) {
       if (listeners[i] == WorkThreadProgressListener.class) {
         ((WorkThreadProgressListener) listeners[i + 1]).statusUpdate(WorkThreadPool.this, index);
       }
     }
   }
 } // }}}
 // {{{ fireProgressChanged() method
 void fireProgressChanged(WorkThread thread) {
   final Object[] listeners = listenerList.getListenerList();
   if (listeners.length != 0) {
     int index = 0;
     for (int i = 0; i < threads.length; i++) {
       if (threads[i] == thread) {
         index = i;
         break;
       }
     }
     for (int i = listeners.length - 2; i >= 0; i--) {
       if (listeners[i] == WorkThreadProgressListener.class) {
         ((WorkThreadProgressListener) listeners[i + 1])
             .progressUpdate(WorkThreadPool.this, index);
       }
     }
   }
 } // }}}
 // {{{ requestDone() method
 void requestDone() {
   synchronized (lock) {
     requestCount--;
     if (requestCount == 0 && firstAWTRequest != null)
       queueAWTRunner();
   }
 } // }}}
 // {{{ getNextRequest() method
 Request getNextRequest() {
   synchronized (lock) {
     Request request = firstRequest;
     if (request == null)
       return null;
     firstRequest = firstRequest.next;
     if (firstRequest == null)
       lastRequest = null;
     if (request.alreadyRun)
       throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
     request.alreadyRun = true;
     /*
      * StringBuffer buf = new StringBuffer("request queue is now: "); Request
      * _request = request.next; while(_request != null) {
      * buf.append(_request.id); if(_request.next != null) buf.append(",");
      * _request = _request.next; } Log.log(Log.DEBUG,this,buf.toString());
      */
     return request;
   }
 } // }}}
 // }}}
 // {{{ Private members
 // {{{ Instance variables
 private boolean started;
 private ThreadGroup threadGroup;
 private WorkThread[] threads;
 // Request queue
 private Request firstRequest;
 private Request lastRequest;
 private int requestCount;
 // AWT thread magic
 private boolean awtRunnerQueued;
 private Request firstAWTRequest;
 private Request lastAWTRequest;
 private int awtRequestCount;
 private EventListenerList listenerList;
 // }}}
 // {{{ doAWTRequests() method
 /** Must always be called with the lock held. */
 private void doAWTRequests() {
   while (requestCount == 0 && firstAWTRequest != null) {
     doAWTRequest(getNextAWTRequest());
   }
 } // }}}
 // {{{ doAWTRequest() method
 /**
  * Must always be called with the lock held.
  * 
  * @param request
  *          the request to run
  */
 private void doAWTRequest(Request request) {
   // Log.log(Log.DEBUG,this,"Running in AWT thread: " + request);
   try {
     request.run.run();
   } catch (Throwable t) {
   }
   awtRequestCount--;
 } // }}}
 // {{{ queueAWTRunner() method
 /** Must always be called with the lock held. */
 private void queueAWTRunner() {
   if (!awtRunnerQueued) {
     awtRunnerQueued = true;
     SwingUtilities.invokeLater(new RunRequestsInAWTThread());
     // Log.log(Log.DEBUG,this,"AWT runner queued");
   }
 } // }}}
 // {{{ getNextAWTRequest() method
 private Request getNextAWTRequest() {
   Request request = firstAWTRequest;
   firstAWTRequest = firstAWTRequest.next;
   if (firstAWTRequest == null)
     lastAWTRequest = null;
   if (request.alreadyRun)
     throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
   request.alreadyRun = true;
   /*
    * StringBuffer buf = new StringBuffer("AWT request queue is now: ");
    * Request _request = request.next; while(_request != null) {
    * buf.append(_request.id); if(_request.next != null) buf.append(",");
    * _request = _request.next; } Log.log(Log.DEBUG,this,buf.toString());
    */
   return request;
 } // }}}
 // }}}
 static int ID;
 // {{{ Request class
 static class Request {
   int id = ++ID;
   Runnable run;
   boolean alreadyRun;
   Request next;
   Request(Runnable run) {
     this.run = run;
   }
   public String toString() {
     return "[id=" + id + ",run=" + run + "]";
   }
 } // }}}
 // {{{ RunRequestsInAWTThread class
 class RunRequestsInAWTThread implements Runnable {
   public void run() {
     synchronized (lock) {
       awtRunnerQueued = false;
       if (requestCount == 0)
         doAWTRequests();
     }
   }
 } // }}}

} /*

* WorkThread.java - Background thread that does stuff Copyright (C) 2000 Slava
* Pestov
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/**

* Services work requests in the background.
* 
* @author Slava Pestov
* @version $Id: WorkThread.java 12504 2008-04-22 23:12:43Z ezust $
*/

class WorkThread extends Thread implements ThreadAbortMonitor {

 public WorkThread(WorkThreadPool pool, ThreadGroup group, String name) {
   super(group, name);
   // so that jEdit doesn"t exit with no views open automatically
   // setDaemon(true);
   setPriority(Thread.MIN_PRIORITY);
   this.pool = pool;
 }
 /**
  * Sets if the current request can be aborted. If set to true and already
  * aborted, the thread will be stopped
  * 
  * @param abortable
  *          true if the WorkThread is abortable
  * @since jEdit 2.6pre1
  */
 public void setAbortable(boolean abortable) {
   synchronized (abortLock) {
     this.abortable = abortable;
     if (aborted)
       stop(new Abort());
   }
 }
 /**
  * Returns if the work thread is currently running a request.
  * 
  * @return true if a request is currently running
  */
 public boolean isRequestRunning() {
   return requestRunning;
 }
 public boolean isAborted() {
   synchronized (abortLock) {
     return aborted;
   }
 }
 /**
  * Returns the status text.
  * 
  * @return the status label
  */
 public String getStatus() {
   return status;
 }
 /**
  * Sets the status text.
  * 
  * @param status
  *          the new status of the thread
  * @since jEdit 2.6pre1
  */
 public void setStatus(String status) {
   this.status = status;
   pool.fireProgressChanged(this);
 }
 /**
  * Returns the progress value.
  * 
  * @return the progress value
  */
 public int getProgressValue() {
   return progressValue;
 }
 /**
  * Sets the progress value.
  * 
  * @param progressValue
  *          the new progress value
  * @since jEdit 2.6pre1
  */
 public void setProgressValue(int progressValue) {
   this.progressValue = progressValue;
   pool.fireProgressChanged(this);
 }
 /**
  * Returns the progress maximum.
  * 
  * @return the maximum value of the progression
  */
 public int getProgressMaximum() {
   return progressMaximum;
 }
 /**
  * Sets the maximum progress value.
  * 
  * @param progressMaximum
  *          the maximum value of the progression
  * @since jEdit 2.6pre1
  */
 public void setProgressMaximum(int progressMaximum) {
   this.progressMaximum = progressMaximum;
   pool.fireProgressChanged(this);
 }
 /**
  * Aborts the currently running request, if allowed.
  * 
  * @since jEdit 2.6pre1
  */
 public void abortCurrentRequest() {
   synchronized (abortLock) {
     if (abortable && !aborted)
       stop(new Abort());
     aborted = true;
   }
 }
 public void run() {
   for (;;) {
     doRequests();
   }
 }
 // private members
 private WorkThreadPool pool;
 private final Object abortLock = new Object();
 private boolean requestRunning;
 private boolean abortable;
 private boolean aborted;
 private String status;
 private int progressValue;
 private int progressMaximum;
 private void doRequests() {
   WorkThreadPool.Request request;
   for (;;) {
     request = pool.getNextRequest();
     if (request == null)
       break;
     else {
       requestRunning = true;
       pool.fireStatusChanged(this);
       doRequest(request);
       requestRunning = false;
     }
   }
   pool.fireStatusChanged(this);
   synchronized (pool.waitForAllLock) {
     // notify a running waitForRequests() method
     pool.waitForAllLock.notifyAll();
   }
   synchronized (pool.lock) {
     // wait for more requests
     try {
       pool.lock.wait();
     } catch (InterruptedException ie) {
     }
   }
 }
 private void doRequest(WorkThreadPool.Request request) {
   try {
     request.run.run();
   } catch (Throwable t) {
   } finally {
     synchronized (abortLock) {
       aborted = abortable = false;
     }
     status = null;
     progressValue = progressMaximum = 0;
     pool.requestDone();
     pool.fireStatusChanged(this);
   }
 }
 public static class Abort extends Error {
   public Abort() {
     super("Work request aborted");
   }
 }

} /*

* ThreadAbortMonitor.java - Thread Abort Monitor
* :tabSize=8:indentSize=8:noTabs=false: :folding=explicit:collapseFolds=1:
* 
* Copyright (C) 2006 Matthieu Casanova
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/**

* @author Matthieu Casanova
* @author $Id: VFS.java 7129 2006-09-25 20:05:57Z kpouer $
*/

interface ThreadAbortMonitor {

 boolean isAborted();

} /*

* WorkThreadProgressListener.java - Progress listener Copyright (C) 2000 Slava
* Pestov
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/**

* A work thread execution progress listener.
* 
* @since jEdit 2.6pre1
*/

interface WorkThreadProgressListener extends EventListener {

 // status message changed, operation started, operation ends, ...
 void statusUpdate(WorkThreadPool threadPool, int threadIndex);
 // progress bar value change
 void progressUpdate(WorkThreadPool threadPool, int threadIndex);

}


 </source>
   
  
 
  



Detect Event Dispatch Thread rule violations

   <source lang="java">

/*

* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

import java.lang.ref.WeakReference; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; /**

*

* This class is used to detect Event Dispatch Thread rule violations
* See *

* 
* @author Scott Delap
* @author Alexander Potochkin
* 
* https://swinghelper.dev.java.net/
*/

public class CheckThreadViolationRepaintManager extends RepaintManager {

 // it is recommended to pass the complete check
 private boolean completeCheck = true;
 private WeakReference<JComponent> lastComponent;
 public CheckThreadViolationRepaintManager(boolean completeCheck) {
   this.rupleteCheck = completeCheck;
 }
 public CheckThreadViolationRepaintManager() {
   this(true);
 }
 public boolean isCompleteCheck() {
   return completeCheck;
 }
 public void setCompleteCheck(boolean completeCheck) {
   this.rupleteCheck = completeCheck;
 }
 public synchronized void addInvalidComponent(JComponent component) {
   checkThreadViolations(component);
   super.addInvalidComponent(component);
 }
 public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
   checkThreadViolations(component);
   super.addDirtyRegion(component, x, y, w, h);
 }
 private void checkThreadViolations(JComponent c) {
   if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
     boolean repaint = false;
     boolean fromSwing = false;
     boolean imageUpdate = false;
     StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
     for (StackTraceElement st : stackTrace) {
       if (repaint && st.getClassName().startsWith("javax.swing.")) {
         fromSwing = true;
       }
       if (repaint && "imageUpdate".equals(st.getMethodName())) {
         imageUpdate = true;
       }
       if ("repaint".equals(st.getMethodName())) {
         repaint = true;
         fromSwing = false;
       }
     }
     if (imageUpdate) {
       // assuming it is java.awt.image.ImageObserver.imageUpdate(...)
       // image was asynchronously updated, that"s ok
       return;
     }
     if (repaint && !fromSwing) {
       // no problems here, since repaint() is thread safe
       return;
     }
     // ignore the last processed component
     if (lastComponent != null && c == lastComponent.get()) {
       return;
     }
     lastComponent = new WeakReference<JComponent>(c);
     violationFound(c, stackTrace);
   }
 }
 protected void violationFound(JComponent c, StackTraceElement[] stackTrace) {
   System.out.println();
   System.out.println("EDT violation detected");
   System.out.println(c);
   for (StackTraceElement st : stackTrace) {
     System.out.println("\tat " + st);
   }
 }
 public static void main(String[] args) throws Exception {
   // set CheckThreadViolationRepaintManager
   RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
   // Valid code
   SwingUtilities.invokeAndWait(new Runnable() {
     public void run() {
       test();
     }
   });
   System.out.println("Valid code passed...");
   repaintTest();
   System.out.println("Repaint test - correct code");
   // Invalide code (stack trace expected)
   test();
 }
 static void test() {
   JFrame frame = new JFrame("Am I on EDT?");
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.add(new JButton("JButton"));
   frame.pack();
   frame.setVisible(true);
   frame.dispose();
 }
 // this test must pass
 static void imageUpdateTest() {
   JFrame frame = new JFrame();
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   JEditorPane editor = new JEditorPane();
   frame.setContentPane(editor);
   editor.setContentType("text/html");
   // it works with no valid image as well
   editor.setText("<html><img src=\"file:\\lala.png\"></html>");
   frame.setSize(300, 200);
   frame.setVisible(true);
 }
 private static JButton test;
 static void repaintTest() {
   try {
     SwingUtilities.invokeAndWait(new Runnable() {
       public void run() {
         test = new JButton();
         test.setSize(100, 100);
       }
     });
   } catch (Exception e) {
     e.printStackTrace();
   }
   // repaint(Rectangle) should be ok
   test.repaint(test.getBounds());
   test.repaint(0, 0, 100, 100);
   test.repaint();
 }

}

 </source>
   
  
 
  



Generic class to dispatch events in a highly reliable way.

   <source lang="java">

/*

  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

import java.awt.EventQueue; import java.util.List; import java.lang.reflect.InvocationTargetException; /**

* Generic class to dispatch events in a highly reliable way.
*
* @author 
* @version $Id: EventDispatcher.java 579228 2007-09-25 12:50:46Z cam $
*/

public class EventDispatcher {

   public interface Dispatcher {
       void dispatch(Object listener,
                            Object event);
   }
   public static void fireEvent(final Dispatcher dispatcher,
                                final List listeners,
                                final Object evt,
                                final boolean useEventQueue) {
       if (useEventQueue && !EventQueue.isDispatchThread()) {
           Runnable r = new Runnable() {
                   public void run() {
                       fireEvent(dispatcher, listeners, evt, useEventQueue);
                   }
               };
           try {
               EventQueue.invokeAndWait(r);
           } catch (InvocationTargetException e) {
               e.printStackTrace();
           } catch (InterruptedException e) {
               // Assume they will get delivered????
               // be nice to wait on List but how???
           } catch (ThreadDeath td) {
               throw td;
           } catch (Throwable t) {
               t.printStackTrace();
           }
           return;
       }
       Object [] ll = null;
       Throwable err = null;
       int retryCount = 10;
       while (--retryCount != 0) {
           // If the thread has been interrupted this can "mess up"
           // the class loader and cause this otherwise safe code to
           // throw errors.
           try {
               synchronized (listeners) {
                   if (listeners.size() == 0)
                       return;
                   ll = listeners.toArray();
                   break;
               }
           } catch(Throwable t) {
               err = t;
           }
       }
       if (ll == null) {
           if (err != null)
               err.printStackTrace();
           return;
       }
       dispatchEvent(dispatcher, ll, evt);
   }
   protected static void dispatchEvent(final Dispatcher dispatcher,
                                       final Object [] ll,
                                       final Object evt) {
       ThreadDeath td = null;
       try {
           for (int i = 0; i < ll.length; i++) {
               try {
                   Object l;
                   synchronized (ll) {
                       l = ll[i];
                       if (l == null) continue;
                       ll[i] = null;
                   }
                   dispatcher.dispatch(l, evt);
               } catch (ThreadDeath t) {
                   // Keep delivering messages but remember to throw later.
                   td = t;
               } catch (Throwable t) {
                   t.printStackTrace();
               }
           }
       } catch (ThreadDeath t) {
           // Remember to throw later.
           td = t;
       } catch (Throwable t) {
           if (ll[ll.length-1] != null)
               dispatchEvent(dispatcher, ll, evt);
           t.printStackTrace();
       }
       if (td != null) throw td;
   }

}

 </source>
   
  
 
  



Process On Swing Event Thread

   <source lang="java">
  

/*

* Copyright (C) 2001-2004 Colin Bell
* colbell@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.awt.ruponent; import java.awt.Container; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; import java.awt.geom.Rectangle2D; import java.beans.PropertyVetoException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.SwingUtilities; /**

* Common GUI utilities accessed via static methods.
* 
* @author 
*/

public class GUIUtils {

 public static void processOnSwingEventThread(Runnable todo) {
   processOnSwingEventThread(todo, false);
 }
 public static void processOnSwingEventThread(Runnable todo, boolean wait) {
   if (todo == null) {
     throw new IllegalArgumentException("Runnable == null");
   }
   if (wait) {
     if (SwingUtilities.isEventDispatchThread()) {
       todo.run();
     } else {
       try {
         SwingUtilities.invokeAndWait(todo);
       } catch (Exception ex) {
         throw new RuntimeException(ex);
       }
     }
   } else {
     if (SwingUtilities.isEventDispatchThread()) {
       todo.run();
     } else {
       SwingUtilities.invokeLater(todo);
     }
   }
 }

}


 </source>
   
  
 
  



SwingWorker in Java 6

   <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 Main{

 public static void main(String[] args) {
   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(progressBar);
   JFrame frame = new JFrame();
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.setContentPane(cp);
   frame.pack();
   frame.setVisible(true);
 }

} class CounterTask extends SwingWorker<Integer, Integer> {

 int DELAY = 1000;
 @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) {
     System.out.println(chunks);
 }
 @Override
 protected void done() {
   if (isCancelled())
     System.out.println("Cancelled !");
   else
     System.out.println("Done !");
 }

}


 </source>
   
  
 
  



Use SwingWorker to perform background tasks

   <source lang="java">
  

import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingWorker; public class Main extends JFrame {

 public Main() {
   this.setLayout(new FlowLayout());
   this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   JButton processButton = new JButton("Start");
   JButton helloButton = new JButton("Hello");
   processButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent event) {
       MyTask process = new MyTask();
       try {
         process.execute();
       } catch (Exception e) {
         e.printStackTrace();
       }
     }
   });
   helloButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       JOptionPane.showMessageDialog(null, "Hello There");
     }
   });
   this.getContentPane().add(processButton);
   this.getContentPane().add(helloButton);
   this.pack();
   setVisible(true);
 }
 public static void main(String[] args) {
   new Main();
 }

} class MyTask extends SwingWorker {

 protected Object doInBackground() throws Exception {
   Integer result = new Integer(0);
   for (int i = 0; i < 10; i++) {
     result += i * 10;
     try {
       Thread.sleep(5000);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
   return result;
 }

}


 </source>
   
  
 
  



Use SwingWorker to wrap time consuming task

   <source lang="java">
   

import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigInteger; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingWorker; public class PrimeCheck extends JFrame {

 public PrimeCheck() {
   setDefaultCloseOperation(EXIT_ON_CLOSE);
   JPanel pnl = new JPanel();
   JButton btnCheck = new JButton("Check");
   ActionListener al;
   al = new ActionListener() {
     public void actionPerformed(ActionEvent ae) {
       try {
         BigInteger bi = new BigInteger("1234567");
         System.out.println("One moment...");
         new PrimeCheckTask(bi).execute();
       } catch (NumberFormatException nfe) {
         System.out.println("Invalid input");
       }
     }
   };
   btnCheck.addActionListener(al);
   pnl.add(btnCheck);
   getContentPane().add(pnl, BorderLayout.NORTH);
   pack();
   setResizable(false);
   setVisible(true);
 }
 public static void main(String[] args) {
       new PrimeCheck();
 }

} class PrimeCheckTask extends SwingWorker<Boolean, Void> {

 private BigInteger bi;
 PrimeCheckTask(BigInteger bi) {
   this.bi = bi;
 }
 @Override
 public Boolean doInBackground() {
   return bi.isProbablePrime(1000);
 }
 @Override
 public void done() {
   try {
       boolean isPrime = get();
       if (isPrime)
         System.out.println("Integer is prime");
       else
         System.out.println("Integer is not prime");
   } catch (Exception ee) {
     System.out.println("Unable to determine primeness");
   }
 }

}


 </source>