Java/Event/General Event — различия между версиями
Admin (обсуждение | вклад) м (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());
}
}