Java/Event/General Event — различия между версиями

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

Текущая версия на 05:58, 1 июня 2010

Event Listener List

    
/**
 * The utillib library.
 * More information is available at http://www.jinchess.ru/.
 * Copyright (C) 2002 Alexander Maryanovsky.
 * All rights reserved.
 *
 * The utillib 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 of the
 * License, or (at your option) any later version.
 *
 * The utillib 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 utillib library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import java.util.EventListener;
import java.lang.reflect.Array;

/**
 * A convenient storage place for Listeners. The listeners are stored in the
 * same manner as in javax.swing.event.EventListenerList.
 * <STRONG>Note:</STRONG> This class is not thread safe.
 */
public class EventListenerList{

  /**
   * The array where we keep the listeners and their types.
   */
  private Object [] listenerList = new Object[0];

  /**
   * Adds the given listener as a listener of the given type.
   */
  public void add(Class listenerType, EventListener listener){
    if (listener==null)
      return;
    if (!listenerType.isInstance(listener))
      throw new IllegalArgumentException("The listener is not an instance of the listener class.");
    Object [] tempArr = new Object[listenerList.length+2];
    System.arraycopy(listenerList,0,tempArr,0,listenerList.length);
    tempArr[tempArr.length-2] = listenerType;
    tempArr[tempArr.length-1] = listener;
    listenerList = tempArr;
  }

  
  /**
   * Removes the given listener as a listener of the specified type.
   */
  public void remove(Class listenerType, EventListener listener){
    if (listener == null)
      return;
    if (!listenerType.isInstance(listener))
      throw new IllegalArgumentException("The listener is not an instance of the listener class.");
    for (int i=0;i<listenerList.length;i+=2){
      if ((listenerList[i]==listenerType)&&(listenerList[i+1].equals(listener))){
        Object [] tempArr = new Object[listenerList.length-2];
        System.arraycopy(listenerList,0,tempArr,0,i);
        System.arraycopy(listenerList,i+2,tempArr,i,listenerList.length-i-2);
        listenerList = tempArr;
        return;
      }
    }
  }

  /**
   * Returns the total number of listeners for this listener list.
   */
  public int getListenerCount(){
    return listenerList.length;
  }

  /**
   * Returns the amount of listeners of the specified type in this listener
   * list.
   */
  public int getListenerCount(Class listenerType){
    int count = 0;
    for (int i=0;i<listenerList.length;i+=2){
      if (listenerList[i]==listenerType)
        count++;
    }
    return count;
  }

  /**
   * Returns an array containing all the listeners in this listener list. The
   * array contains listeners and their types in the following format: the
   * element at index 2*N is the type of the listener at index 2*N+1
   * <B>WARNING!!!</B> Absolutely NO modification of the data contained in this array
   * should be made -- if any such manipulation is necessary, it should be done on a
   * copy of the array returned rather than the array itself.
   */
  public Object [] getListenerList(){
    return listenerList;
  }

  /**
   * Returns an array of listeners registered as the listeners of the given
   * type. Note that the returned array is an array of the actual given type
   * so it can be safely casted to that type once instead of casting each of the
   * listener.
   */
  public EventListener [] getListeners(Class listenerType){
    EventListener [] listeners = (EventListener [])Array.newInstance(listenerType,getListenerCount(listenerType));
    int count = 0;
    for (int i=0;i<listenerList.length;i+=2){
      if (listenerType==listenerList[i])
        listeners[count++] = (EventListener)listenerList[i+1];
    }
    return listeners;
  }

}





EventTest Pane

   
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ruponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A program that displays all the event that occur in its window */
public class EventTestPane extends JPanel {
  /** The constructor: register the event types we are interested in */
  public EventTestPane() {
    // We"re interested in all types of events
    this.enableEvents(AWTEvent.MOUSE_EVENT_MASK
        | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.KEY_EVENT_MASK
        | AWTEvent.FOCUS_EVENT_MASK | AWTEvent.ruPONENT_EVENT_MASK
        | AWTEvent.WINDOW_EVENT_MASK);
    this.setPreferredSize(new Dimension(500, 400));
  }
  /**
   * Display mouse events that don"t involve mouse motion. The mousemods()
   * method prints modifiers, and is defined below. The other methods return
   * additional information about the mouse event. showLine() displays a line
   * of text in the window. It is defined at the end of this class, along with
   * the paintComponent() method.
   */
  public void processMouseEvent(MouseEvent e) {
    String type = null;
    switch (e.getID()) {
    case MouseEvent.MOUSE_PRESSED:
      type = "MOUSE_PRESSED";
      break;
    case MouseEvent.MOUSE_RELEASED:
      type = "MOUSE_RELEASED";
      break;
    case MouseEvent.MOUSE_CLICKED:
      type = "MOUSE_CLICKED";
      break;
    case MouseEvent.MOUSE_ENTERED:
      type = "MOUSE_ENTERED";
      break;
    case MouseEvent.MOUSE_EXITED:
      type = "MOUSE_EXITED";
      break;
    }
    showLine(mousemods(e) + type + ": [" + e.getX() + "," + e.getY() + "] "
        + "num clicks = " + e.getClickCount()
        + (e.isPopupTrigger() ? "; is popup trigger" : ""));
    // When the mouse enters the component, request keyboard focus so
    // we can receive and respond to keyboard events
    if (e.getID() == MouseEvent.MOUSE_ENTERED)
      requestFocus();
  }
  /**
   * Display mouse moved and dragged mouse event. Note that MouseEvent is the
   * only event type that has two methods, two EventListener interfaces and
   * two adapter classes to handle two distinct categories of events. Also, as
   * seen in init(), mouse motion events must be requested separately from
   * other mouse event types.
   */
  public void processMouseMotionEvent(MouseEvent e) {
    String type = null;
    switch (e.getID()) {
    case MouseEvent.MOUSE_MOVED:
      type = "MOUSE_MOVED";
      break;
    case MouseEvent.MOUSE_DRAGGED:
      type = "MOUSE_DRAGGED";
      break;
    }
    showLine(mousemods(e) + type + ": [" + e.getX() + "," + e.getY() + "] "
        + "num clicks = " + e.getClickCount()
        + (e.isPopupTrigger() ? "; is popup trigger" : ""));
  }
  /**
   * Return a string representation of the modifiers for a MouseEvent. Note
   * that the methods called here are inherited from InputEvent.
   */
  protected String mousemods(MouseEvent e) {
    int mods = e.getModifiers();
    String s = "";
    if (e.isShiftDown())
      s += "Shift ";
    if (e.isControlDown())
      s += "Ctrl ";
    if ((mods & InputEvent.BUTTON1_MASK) != 0)
      s += "Button 1 ";
    if ((mods & InputEvent.BUTTON2_MASK) != 0)
      s += "Button 2 ";
    if ((mods & InputEvent.BUTTON3_MASK) != 0)
      s += "Button 3 ";
    return s;
  }
  /**
   * Display keyboard events.
   * 
   * Note that there are three distinct types of key events, and that key
   * events are reported by key code and/or Unicode character. KEY_PRESSED and
   * KEY_RELEASED events are generated for all key strokes. KEY_TYPED events
   * are only generated when a key stroke produces a Unicode character; these
   * events do not report a key code. If isActionKey() returns true, then the
   * key event reports only a key code, because the key that was pressed or
   * released (such as a function key) has no corresponding Unicode character.
   * Key codes can be interpreted by using the many VK_ constants defined by
   * the KeyEvent class, or they can be converted to strings using the static
   * getKeyText() method as we do here.
   */
  public void processKeyEvent(KeyEvent e) {
    String eventtype, modifiers, code, character;
    switch (e.getID()) {
    case KeyEvent.KEY_PRESSED:
      eventtype = "KEY_PRESSED";
      break;
    case KeyEvent.KEY_RELEASED:
      eventtype = "KEY_RELEASED";
      break;
    case KeyEvent.KEY_TYPED:
      eventtype = "KEY_TYPED";
      break;
    default:
      eventtype = "UNKNOWN";
    }
    // Convert the list of modifier keys to a string
    modifiers = KeyEvent.getKeyModifiersText(e.getModifiers());
    // Get string and numeric versions of the key code, if any.
    if (e.getID() == KeyEvent.KEY_TYPED)
      code = "";
    else
      code = "Code=" + KeyEvent.getKeyText(e.getKeyCode()) + " ("
          + e.getKeyCode() + ")";
    // Get string and numeric versions of the Unicode character, if any.
    if (e.isActionKey())
      character = "";
    else
      character = "Character=" + e.getKeyChar() + " (Unicode="
          + ((int) e.getKeyChar()) + ")";
    // Display it all.
    showLine(eventtype + ": " + modifiers + " " + code + " " + character);
  }
  /**
   * Display keyboard focus events. Focus can be permanently gained or lost,
   * or temporarily transferred to or from a component.
   */
  public void processFocusEvent(FocusEvent e) {
    if (e.getID() == FocusEvent.FOCUS_GAINED)
      showLine("FOCUS_GAINED" + (e.isTemporary() ? " (temporary)" : ""));
    else
      showLine("FOCUS_LOST" + (e.isTemporary() ? " (temporary)" : ""));
  }
  /** Display Component events. */
  public void processComponentEvent(ComponentEvent e) {
    switch (e.getID()) {
    case ComponentEvent.ruPONENT_MOVED:
      showLine("COMPONENT_MOVED");
      break;
    case ComponentEvent.ruPONENT_RESIZED:
      showLine("COMPONENT_RESIZED");
      break;
    case ComponentEvent.ruPONENT_HIDDEN:
      showLine("COMPONENT_HIDDEN");
      break;
    case ComponentEvent.ruPONENT_SHOWN:
      showLine("COMPONENT_SHOWN");
      break;
    }
  }
  /** Display Window events. Note the special handling of WINDOW_CLOSING */
  public void processWindowEvent(WindowEvent e) {
    switch (e.getID()) {
    case WindowEvent.WINDOW_OPENED:
      showLine("WINDOW_OPENED");
      break;
    case WindowEvent.WINDOW_CLOSED:
      showLine("WINDOW_CLOSED");
      break;
    case WindowEvent.WINDOW_CLOSING:
      showLine("WINDOW_CLOSING");
      break;
    case WindowEvent.WINDOW_ICONIFIED:
      showLine("WINDOW_ICONIFIED");
      break;
    case WindowEvent.WINDOW_DEICONIFIED:
      showLine("WINDOW_DEICONIFIED");
      break;
    case WindowEvent.WINDOW_ACTIVATED:
      showLine("WINDOW_ACTIVATED");
      break;
    case WindowEvent.WINDOW_DEACTIVATED:
      showLine("WINDOW_DEACTIVATED");
      break;
    }
    // If the user requested a window close, quit the program.
    // But first display a message, force it to be visible, and make
    // sure the user has time to read it.
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      showLine("WINDOW_CLOSING event received.");
      showLine("Application will exit in 5 seconds");
      // Force the updates to appear now.
      update(this.getGraphics());
      // Wait five seconds
      try {
        Thread.sleep(5000);
      } catch (InterruptedException ie) {
        ;
      }
      // Exit now
      System.exit(0);
    }
  }
  /** The list of lines to display in the window */
  protected Vector lines = new Vector();
  /** Add a new line to the list of lines, and request redisplay */
  protected void showLine(String s) {
    if (lines.size() == 20)
      lines.removeElementAt(0);
    lines.addElement(s);
    repaint();
  }
  /** This method repaints the text in the window */
  public void paintComponent(Graphics g) {
    for (int i = 0; i < lines.size(); i++)
      g.drawString((String) lines.elementAt(i), 20, i * 16 + 50);
  }
  public boolean isOpaque() {
    return false;
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    frame.getContentPane().add(new EventTestPane(), BorderLayout.CENTER);
    // Finally, set the size of the main window, and pop it up.
    frame.setSize(600, 400);
    frame.setVisible(true);
  }
}





KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner()

   
import java.awt.KeyboardFocusManager;
public class Main {
  public static void main(String[] argv) throws Exception {
    KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
  }
}





Monitors the AWT event dispatch thread for events that take longer than a certain time to be dispatched

  
/*
 * 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.awt.*;
import java.awt.event.*;
import java.lang.management.*;
import java.util.*;
import java.util.Timer;
import javax.swing.*;
/**
 * Monitors the AWT event dispatch thread for events that take longer than
 * a certain time to be dispatched.
 * <p/>
 * The principle is to record the time at which we start processing an event,
 * and have another thread check frequently to see if we"re still processing.
 * If the other thread notices that we"ve been processing a single event for
 * too long, it prints a stack trace showing what the event dispatch thread
 * is doing, and continues to time it until it finally finishes.
 * <p/>
 * This is useful in determining what code is causing your Java application"s
 * GUI to be unresponsive.
 * 
 * <p>The original blog can be found here<br>  
 * 
 * </p>
 *
 * @author Elliott Hughes <enh@jessies.org>
 * 
 * Advice, bug fixes, and test cases from
 * Alexander Potochkin and Oleg Sukhodolsky.
 * 
 * https://swinghelper.dev.java.net/
 */
public final class EventDispatchThreadHangMonitor extends EventQueue {
    private static final EventDispatchThreadHangMonitor INSTANCE = new EventDispatchThreadHangMonitor();
    // Time to wait between checks that the event dispatch thread isn"t hung.
    private static final long CHECK_INTERVAL_MS = 100;
    // Maximum time we won"t warn about. This used to be 500 ms, but 1.5 on
    // late-2004 hardware isn"t really up to it; there are too many parts of
    // the JDK that can go away for that long (often code that has to be
    // called on the event dispatch thread, like font loading).
    private static final long UNREASONABLE_DISPATCH_DURATION_MS = 1000;
    // Help distinguish multiple hangs in the log, and match start and end too.
    // Only access this via getNewHangNumber.
    private static int hangCount = 0;
    // Prevents us complaining about hangs during start-up, which are probably
    // the JVM vendor"s fault.
    private boolean haveShownSomeComponent = false;
    // The currently outstanding event dispatches. The implementation of
    // modal dialogs is a common cause for multiple outstanding dispatches.
    private final LinkedList<DispatchInfo> dispatches = new LinkedList<DispatchInfo>();
    private static class DispatchInfo {
        // The last-dumped hung stack trace for this dispatch.
        private StackTraceElement[] lastReportedStack;
        // If so; what was the identifying hang number?
        private int hangNumber;
        // The EDT for this dispatch (for the purpose of getting stack traces).
        // I don"t know of any API for getting the event dispatch thread,
        // but we can assume that it"s the current thread if we"re in the
        // middle of dispatching an AWT event...
        // We can"t cache this because the EDT can die and be replaced by a
        // new EDT if there"s an uncaught exception.
        private final Thread eventDispatchThread = Thread.currentThread();
        // The last time in milliseconds at which we saw a dispatch on the above thread.
        private long lastDispatchTimeMillis = System.currentTimeMillis();
        public DispatchInfo() {
            // All initialization is done by the field initializers.
        }
        public void checkForHang() {
            if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) {
                examineHang();
            }
        }
        // We can"t use StackTraceElement.equals because that insists on checking the filename and line number.
        // That would be version-specific.
        private static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) {
            return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative;
        }
        // Checks whether the given stack looks like it"s waiting for another event.
        // This relies on JDK implementation details.
        private boolean isWaitingForNextEvent(StackTraceElement[] currentStack) {
            return stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true) && stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false) && stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false);
        }
        private void examineHang() {
            StackTraceElement[] currentStack = eventDispatchThread.getStackTrace();
            if (isWaitingForNextEvent(currentStack)) {
                // Don"t be fooled by a modal dialog if it"s waiting for its next event.
                // As long as the modal dialog"s event pump doesn"t get stuck, it"s okay for the outer pump to be suspended.
                return;
            }
            if (stacksEqual(lastReportedStack, currentStack)) {
                // Don"t keep reporting the same hang every time the timer goes off.
                return;
            }
            hangNumber = getNewHangNumber();
            String stackTrace = stackTraceToString(currentStack);
            lastReportedStack = currentStack;
            Log.warn("(hang #" + hangNumber + ") event dispatch thread stuck processing event for " + timeSoFar() + " ms:" + stackTrace);
            checkForDeadlock();
        }
        private static boolean stacksEqual(StackTraceElement[] a, StackTraceElement[] b) {
            if (a == null) {
                return false;
            }
            if (a.length != b.length) {
                return false;
            }
            for (int i = 0; i < a.length; ++i) {
                if (a[i].equals(b[i]) == false) {
                    return false;
                }
            }
            return true;
        }
        /**
         * Returns how long this dispatch has been going on (in milliseconds).
         */
        private long timeSoFar() {
            return (System.currentTimeMillis() - lastDispatchTimeMillis);
        }
        public void dispose() {
            if (lastReportedStack != null) {
                Log.warn("(hang #" + hangNumber + ") event dispatch thread unstuck after " + timeSoFar() + " ms.");
            }
        }
    }
    private EventDispatchThreadHangMonitor() {
        initTimer();
    }
    /**
     * Sets up a timer to check for hangs frequently.
     */
    private void initTimer() {
        final long initialDelayMs = 0;
        final boolean isDaemon = true;
        Timer timer = new Timer("EventDispatchThreadHangMonitor", isDaemon);
        timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS);
    }
    private class HangChecker extends TimerTask {
        @Override
        public void run() {
            synchronized (dispatches) {
                if (dispatches.isEmpty() || !haveShownSomeComponent) {
                    // Nothing to do.
                    // We don"t destroy the timer when there"s nothing happening
                    // because it would mean a lot more work on every single AWT
                    // event that gets dispatched.
                    return;
                }
                // Only the most recent dispatch can be hung; nested dispatches
                // by their nature cause the outer dispatch pump to be suspended.
                dispatches.getLast().checkForHang();
            }
        }
    }
    /**
     * Sets up hang detection for the event dispatch thread.
     */
    public static void initMonitoring() {
        Toolkit.getDefaultToolkit().getSystemEventQueue().push(INSTANCE);
    }
    /**
     * Overrides EventQueue.dispatchEvent to call our pre and post hooks either
     * side of the system"s event dispatch code.
     */
    @Override
    protected void dispatchEvent(AWTEvent event) {
        try {
            preDispatchEvent();
            super.dispatchEvent(event);
        } finally {
            postDispatchEvent();
            if (!haveShownSomeComponent && 
                    event instanceof WindowEvent && event.getID() == WindowEvent.WINDOW_OPENED) {
                haveShownSomeComponent = true;
            }
        }
    }
    private void debug(String which) {
        if (false) {
            for (int i = dispatches.size(); i >= 0; --i) {
                System.out.print(" ");
            }
            System.out.println(which);
        }
    }
    /**
     * Starts tracking a dispatch.
     */
    private synchronized void preDispatchEvent() {
        debug("pre");
        synchronized (dispatches) {
            dispatches.addLast(new DispatchInfo());
        }
    }
    /**
     * Stops tracking a dispatch.
     */
    private synchronized void postDispatchEvent() {
        synchronized (dispatches) {
            // We"ve finished the most nested dispatch, and don"t need it any longer.
            DispatchInfo justFinishedDispatch = dispatches.removeLast();
            justFinishedDispatch.dispose();
            // The other dispatches, which have been waiting, need to be credited extra time.
            // We do this rather simplistically by pretending they"ve just been redispatched.
            Thread currentEventDispatchThread = Thread.currentThread();
            for (DispatchInfo dispatchInfo : dispatches) {
                if (dispatchInfo.eventDispatchThread == currentEventDispatchThread) {
                    dispatchInfo.lastDispatchTimeMillis = System.currentTimeMillis();
                }
            }
        }
        debug("post");
    }
    private static void checkForDeadlock() {
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadBean.findMonitorDeadlockedThreads();
        if (threadIds == null) {
            return;
        }
        Log.warn("deadlock detected involving the following threads:");
        ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, Integer.MAX_VALUE);
        for (ThreadInfo info : threadInfos) {
            Log.warn("Thread #" + info.getThreadId() + " " + info.getThreadName() + 
                    " (" + info.getThreadState() + ") waiting on " + info.getLockName() + 
                    " held by " + info.getLockOwnerName() + stackTraceToString(info.getStackTrace()));
        }
    }
    private static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringBuilder result = new StringBuilder();
        // We used to avoid showing any code above where this class gets
        // involved in event dispatch, but that hides potentially useful
        // information when dealing with modal dialogs. Maybe we should
        // reinstate that, but search from the other end of the stack?
        for (StackTraceElement stackTraceElement : stackTrace) {
            String indentation = "    ";
            result.append("\n" + indentation + stackTraceElement);
        }
        return result.toString();
    }
    private synchronized static int getNewHangNumber() {
        return ++hangCount;
    }
    public static void main(String[] args) {
        initMonitoring();
        //special case for deadlock test
        if (args.length > 0 && "deadlock".equals(args[0])) {
            EventDispatchThreadHangMonitor.INSTANCE.haveShownSomeComponent = true;
            Tests.runDeadlockTest();
            return;
        }
        Tests.main(args);
    }
    private static class Tests {
        public static void main(final String[] args) {
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    for (String arg : args) {
                        final JFrame frame = new JFrame();
                        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        frame.setLocationRelativeTo(null);
                        if (arg.equals("exception")) {
                            runExceptionTest(frame);
                        } else if (arg.equals("focus")) {
                            runFocusTest(frame);
                        } else if (arg.equals("modal-hang")) {
                            runModalTest(frame, true);
                        } else if (arg.equals("modal-no-hang")) {
                            runModalTest(frame, false);
                        } else {
                            System.err.println("unknown regression test "" + arg + """);
                            System.exit(1);
                        }
                        frame.pack();
                        frame.setVisible(true);
                    }
                }
            });
        }
        private static void runDeadlockTest() {
            class Locker {
                private Locker locker;
                public void setLocker(Locker locker) {
                    this.locker = locker;
                }
                public synchronized void tryToDeadlock() {
                    locker.toString();
                }
                public synchronized String toString() {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return super.toString();
                }
            }
            final Locker one = new Locker();
            final Locker two = new Locker();
            one.setLocker(two);
            two.setLocker(one);
            //Deadlock expected here:
            for (int i = 0; i < 100; i++) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        one.tryToDeadlock();
                    }
                });
                two.tryToDeadlock();
            }
        }
        // If we don"t do our post-dispatch activity in a finally block, we"ll
        // report bogus hangs.
        private static void runExceptionTest(final JFrame frame) {
            JButton button = new JButton("Throw Exception");
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // This shouldn"t cause us to report a hang.
                    throw new RuntimeException("Nobody expects the Spanish Inquisition!");
                }
            });
            frame.add(button);
        }
        // A demonstration of nested calls to dispatchEvent caused by SequencedEvent.
        private static void runFocusTest(final JFrame frame) {
            final JDialog dialog = new JDialog(frame, "Non-Modal Dialog");
            dialog.add(new JLabel("Close me!"));
            dialog.pack();
            dialog.setLocationRelativeTo(frame);
            dialog.addWindowFocusListener(new WindowAdapter() {
                public void windowGainedFocus(WindowEvent e) {
                    System.out.println("FocusTest.windowGainedFocus");
                    // If you don"t cope with nested calls to dispatchEvent, you won"t detect this.
                    // See java.awt.SequencedEvent for an example.
                    sleep(2500);
                }
            });
            JButton button = new JButton("Show Non-Modal Dialog");
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    dialog.setVisible(true);
                }
            });
            frame.add(button);
        }
        // A demonstration of the problems of dealing with modal dialogs.
        private static void runModalTest(final JFrame frame, final boolean shouldSleep) {
            System.out.println(shouldSleep ? "Expect hangs!" : "There should be no hangs...");
            JButton button = new JButton("Show Modal Dialog");
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (shouldSleep) {
                        sleep(2500); // This is easy.
                    }
                    JDialog dialog = new JDialog(frame, "Modal dialog", true);
                    dialog.setLayout(new FlowLayout());
                    dialog.add(new JLabel("Close this dialog!"));
                    final JLabel label = new JLabel(" ");
                    dialog.add(label);
                    dialog.pack();
                    dialog.setLocation(frame.getX() - 100, frame.getY());
                    // Make sure the new event pump has some work to do, each unit of which is insufficient to cause a hang.
                    new Thread(new Runnable() {
                        public void run() {
                            for (int i = 0; i <= 100000; ++i) {
                                final int value = i;
                                EventQueue.invokeLater(new Runnable() {
                                    public void run() {
                                        label.setText(Integer.toString(value));
                                    }
                                });
                            }
                        }
                    }).start();
                    dialog.setVisible(true);
                    if (shouldSleep) {
                        sleep(2500); // If you don"t distinguish different stack traces, you won"t report this.
                    }
                }
            });
            frame.add(button);
        }
        private static void sleep(long ms) {
            try {
                System.out.println("Sleeping for " + ms + " ms on " + Thread.currentThread() + "...");
                Thread.sleep(ms);
                System.out.println("Finished sleeping...");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    private static class Log {
        public static void warn(String str) {
            System.out.println(str);
        }
    }
}





Multicast event

   
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MulticastEvent extends JPanel implements ActionListener {
  private int counter = 0;
  private JButton closeAllButton;
  public MulticastEvent() {
    JButton newButton = new JButton("New");
    add(newButton);
    newButton.addActionListener(this);
    closeAllButton = new JButton("Close all");
    add(closeAllButton);
  }
  public void actionPerformed(ActionEvent evt) {
    CloseFrame f = new CloseFrame();
    counter++;
    f.setTitle("Window " + counter);
    f.setSize(200, 150);
    f.setLocation(30 * counter, 30 * counter);
    f.show();
    closeAllButton.addActionListener(f);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("MulticastTest");
    frame.setSize(300, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new MulticastEvent());
    frame.show();
  }
  class CloseFrame extends JFrame implements ActionListener {
    public void actionPerformed(ActionEvent evt) { // handles Close all
                            // button
      setVisible(false);
    }
  }
}





Swing Event MultiListener

   
/* From http://java.sun.ru/docs/books/tutorial/index.html */
/*
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */
/*
 * Swing version
 */
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class MultiListener extends JPanel implements ActionListener {
  JTextArea topTextArea;
  JTextArea bottomTextArea;
  JButton button1, button2;
  final static String newline = "\n";
  public MultiListener() {
    super(new GridBagLayout());
    GridBagLayout gridbag = (GridBagLayout) getLayout();
    GridBagConstraints c = new GridBagConstraints();
    JLabel l = null;
    c.fill = GridBagConstraints.BOTH;
    c.gridwidth = GridBagConstraints.REMAINDER;
    l = new JLabel("What MultiListener hears:");
    gridbag.setConstraints(l, c);
    add(l);
    c.weighty = 1.0;
    topTextArea = new JTextArea();
    topTextArea.setEditable(false);
    JScrollPane topScrollPane = new JScrollPane(topTextArea);
    Dimension preferredSize = new Dimension(200, 75);
    topScrollPane.setPreferredSize(preferredSize);
    gridbag.setConstraints(topScrollPane, c);
    add(topScrollPane);
    c.weightx = 0.0;
    c.weighty = 0.0;
    l = new JLabel("What Eavesdropper hears:");
    gridbag.setConstraints(l, c);
    add(l);
    c.weighty = 1.0;
    bottomTextArea = new JTextArea();
    bottomTextArea.setEditable(false);
    JScrollPane bottomScrollPane = new JScrollPane(bottomTextArea);
    bottomScrollPane.setPreferredSize(preferredSize);
    gridbag.setConstraints(bottomScrollPane, c);
    add(bottomScrollPane);
    c.weightx = 1.0;
    c.weighty = 0.0;
    c.gridwidth = 1;
    c.insets = new Insets(10, 10, 0, 10);
    button1 = new JButton("Blah blah blah");
    gridbag.setConstraints(button1, c);
    add(button1);
    c.gridwidth = GridBagConstraints.REMAINDER;
    button2 = new JButton("You don"t say!");
    gridbag.setConstraints(button2, c);
    add(button2);
    button1.addActionListener(this);
    button2.addActionListener(this);
    button2.addActionListener(new Eavesdropper(bottomTextArea));
    setPreferredSize(new Dimension(450, 450));
    setBorder(BorderFactory.createCompoundBorder(BorderFactory
        .createMatteBorder(1, 1, 2, 2, Color.black), BorderFactory
        .createEmptyBorder(5, 5, 5, 5)));
  }
  public void actionPerformed(ActionEvent e) {
    topTextArea.append(e.getActionCommand() + newline);
    topTextArea.setCaretPosition(topTextArea.getDocument().getLength());
  }
  /**
   * Create the GUI and show it. For thread safety, this method should be
   * invoked from the event-dispatching thread.
   */
  private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    //Create and set up the window.
    JFrame frame = new JFrame("MultiListener");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //Create and set up the content pane.
    JComponent newContentPane = new MultiListener();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);
    //Display the window.
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application"s GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
}
class Eavesdropper implements ActionListener {
  JTextArea myTextArea;
  public Eavesdropper(JTextArea ta) {
    myTextArea = ta;
  }
  public void actionPerformed(ActionEvent e) {
    myTextArea.append(e.getActionCommand() + MultiListener.newline);
    myTextArea.setCaretPosition(myTextArea.getDocument().getLength());
  }
}