Event Dispatching Problem

I use "my own" event processing, mainly to deal with modal dialogs.

publicstaticvoid dispatchEvent(AWTEvent event)

{

assert SwingUtilities.isEventDispatchThread() ;

if (eventinstanceof ActiveEvent){

((ActiveEvent)event).dispatch() ;

}

elseif (sourceinstanceof Component){

((Component)source).dispatchEvent(event) ;

}

elseif (sourceinstanceof MenuComponent){

((MenuComponent)source).dispatchEvent(event) ;

}

else{

thrownew RuntimeException("Unable to dispatch: " + event) ;

}

}

However, sometimes the dipatching blocks on a SequencedEvent. The GUI is frozen and gets only unblocked when interrupting the event dispatching thread. The EDT stack trace tells me in this case:

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:485)

java.awt.EventQueue.getNextEvent(Unknown Source)

java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)

java.awt.EventDispatchThread.pumpEvents(Unknown Source)

java.awt.SequencedEvent.dispatch(Unknown Source)

my.SwingEvent.dispatchEvent(SwingEvent.java:55)

So it appears that the SequencedEvent is not the first in its list; however there are neither any events pending. How can this happen?

Any ideas are highly appreciated! Thx & rgds

[2304 byte] By [Crauda] at [2007-11-27 8:27:43]
# 1
Why oh why?What's the problem with modal dialogs that leads you to this?
dwga at 2007-7-12 20:17:27 > top of Java-index,Desktop,Core GUI APIs...
# 2

Well, basically I try to have somewhat like a sequential flow of control. I don't want to deal with too many callbacks which make the program flow really hard to keep track.

Instead, almost all control is given to the Swing thread. Long lasting operations are transferred to dedicated threads. However, at the end of the thread, a flag ist set with invokeLater; and the Swing thread processes all events at the same time while waiting that this flag becomes true (so it can proceed thereafter in a sequential manner).

Thus I need to have my own dispatch method (as described above). Well, with Motif (or other GUI languages) there was never a problem to process events. Maybe, in Swing, processing events is not as simple? Or not permitted at all? Than I would leave it.

So, is dispatchig events in Swing as described above harmful? Is it possible at all?

thx in advance!

Crauda at 2007-7-12 20:17:27 > top of Java-index,Desktop,Core GUI APIs...
# 3

> Well, basically I try to have somewhat like a

> sequential flow of control. I don't want to deal with

> too many callbacks which make the program flow really

> hard to keep track.

I don't get this point, so by trying to make your code more readable you're inventing your own GUI event dispatching model instead of using what every swing programmer is used to?

dwga at 2007-7-12 20:17:27 > top of Java-index,Desktop,Core GUI APIs...
# 4

Since the problem still persists, here some code to reproduce it.

import java.awt.* ;

import java.awt.event.* ;

import java.util.* ;

import javax.swing.* ;

import javax.swing.event.* ;

class Main

{

static boolean debug ;

static void log(String message)

{

if (debug)

System.err.println(message) ;

}

// we force all execution to the event dispatching thread

public static void main(String[] args)

{

debug = args.length == 1 && args[0].equals("debug") ;

Runnable runnable = new Runnable() {

public void run() { execute() ; }

} ;

SwingUtilities.invokeLater(runnable) ;

}

// local event dispatching controlled by the user

static class SwingEvent

{

static AWTEvent getNextEvent()

{

try {

return Toolkit.getDefaultToolkit().getSystemEventQueue().getNextEvent() ;

}

catch (InterruptedException exception) {

throw new RuntimeException("Interrupted event dispatching") ;

}

}

static void dispatchEvent(AWTEvent event)

{

if (event instanceof ActiveEvent) {

((ActiveEvent)event).dispatch() ;

}

else {

Object source = event.getSource() ;

if (source instanceof Component) {

((Component)source).dispatchEvent(event) ;

}

else if (source instanceof MenuComponent) {

((MenuComponent)source).dispatchEvent(event) ;

}

else {

throw new RuntimeException("Unable to dispatch: " + event) ;

}

}

}

static void processEvent()

{

assert SwingUtilities.isEventDispatchThread() ;

dispatchEvent(getNextEvent()) ;

}

}

// the start method executes the required operation in a dedicated

// thread. however, the method does not return until the operation

// is completed. all new events are processed while the operation

// is in progress. -- this enables some sequential flow of control.

static class Worker

{

boolean finished = false ;

protected void invoke() {} // to be overloaded by the client

private void setFinished()

{

Runnable runnable = new Runnable() {

@Override public void run()

{

finished = true ;

log("set finished") ;

}} ;

SwingUtilities.invokeLater(runnable) ;

}

public void start()

{

assert SwingUtilities.isEventDispatchThread() ;

log("start...") ;

Runnable runnable = new Runnable() {

@Override public void run() {

log("about to invoke...") ;

invoke() ;

log("...invoke finished.") ;

setFinished() ;

}} ;

new Thread(runnable).start() ;

while (!finished) {

log("about to process event...") ;

SwingEvent.processEvent() ;

log("...event processed.") ;

}

log("...finished.") ;

}

}

// the watchdog for the event dispatching thread

static class SwingWatchdog

{

boolean stillWaiting = false ;

Thread swingThread = Thread.currentThread() ;

static void dumpStack(Thread thread)

{

Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces() ;

StackTraceElement[] array = map.get(thread) ;

for (StackTraceElement element : array) {

System.err.println(element) ;

}

}

void poll()

{

while (true) {

stillWaiting = true ;

Runnable runnable = new Runnable() {

@Override public void run() { stillWaiting = false ; }} ;

SwingUtilities.invokeLater(runnable) ;

try { Thread.sleep(5000) ; }

catch (InterruptedException exception) {}

if (stillWaiting) {

System.err.println("Swing did not respond!") ;

dumpStack(swingThread) ;

swingThread.interrupt() ;

}

}

}

public static SwingWatchdog init()

{

assert SwingUtilities.isEventDispatchThread() ;

final SwingWatchdog watchdog = new SwingWatchdog() ;

Runnable runnable = new Runnable() {

@Override public void run() { watchdog.poll() ; }} ;

new Thread(runnable).start() ;

return watchdog ;

}

}

static void execute()

{

final JFrame frame = new JFrame("Problem with SequencedEvent?") ;

// create a list; the list is only used to catch keyboard events...

Integer[] items = new Integer[100] ;

for (int i=0 ; i<100 ; ++i) {

items[i] = i ;

}

JList jList = new JList(items) ;

// ...which start up worker threads

jList.addListSelectionListener(new ListSelectionListener() {

public void valueChanged(ListSelectionEvent event) { processEvent(frame) ; }}) ;

frame.add(jList) ;

frame.setBounds(100, 100, 100, 400) ;

frame.setVisible(true) ;

SwingWatchdog.init() ;

while (true)

SwingEvent.processEvent() ;

}

static void processEvent(JFrame frame)

{

log("process list event...") ;

JDialog dialog = new JDialog(frame, "Please...", false) ;

dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) ;

dialog.add(new JLabel("...wait")) ;

dialog.setLocation(100,200) ;

dialog.pack();

dialog.setVisible(true) ;

new Worker().start() ;

dialog.setVisible(false) ;

log("...list event processed.") ;

}

}

After starting the program (from a terminal), a window appears with a list of numbers. Just click into the list and press and hold thereafter the "down" key on your keyboard. Instead of browsing thru the list, the program gets stuck and nothing happens until the watchdog interrupts the Swing thread. On the terminal should appear a stack trace like:

Swing did not respond!

java.lang.Object.wait(Native Method)

java.lang.Object.wait(Object.java:485)

java.awt.EventQueue.getNextEvent(Unknown Source)

java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)

java.awt.EventDispatchThread.pumpEvents(Unknown Source)

java.awt.SequencedEvent.dispatch(Unknown Source)

Main$SwingEvent.dispatchEvent(Main.java:43)

Main$SwingEvent.processEvent(Main.java:62)

Main$Worker.start(Main.java:101)

Main.processEvent(Main.java:180)

Main$2.valueChanged(Main.java:162)

javax.swing.JList.fireSelectionValueChanged(Unknown Source)

javax.swing.JList$ListSelectionHandler.valueChanged(Unknown Source)

javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)

javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)

javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)

javax.swing.DefaultListSelectionModel.changeSelection(Unknown Source)

javax.swing.DefaultListSelectionModel.changeSelection(Unknown Source)

javax.swing.DefaultListSelectionModel.setSelectionInterval(Unknown Source)

javax.swing.JList.setSelectedIndex(Unknown Source)

javax.swing.plaf.basic.BasicListUI$Actions.changeSelection(Unknown Source)

javax.swing.plaf.basic.BasicListUI$Actions.actionPerformed(Unknown Source)

javax.swing.SwingUtilities.notifyAction(Unknown Source)

javax.swing.JComponent.processKeyBinding(Unknown Source)

javax.swing.JComponent.processKeyBindings(Unknown Source)

javax.swing.JComponent.processKeyEvent(Unknown Source)

java.awt.Component.processEvent(Unknown Source)

java.awt.Container.processEvent(Unknown Source)

java.awt.Component.dispatchEventImpl(Unknown Source)

java.awt.Container.dispatchEventImpl(Unknown Source)

java.awt.Component.dispatchEvent(Unknown Source)

java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)

java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)

java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)

java.awt.DefaultKeyboardFocusManager.pumpApprovedKeyEvents(Unknown Source)

java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)

java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)

java.awt.Component.dispatchEventImpl(Unknown Source)

java.awt.Container.dispatchEventImpl(Unknown Source)

java.awt.Window.dispatchEventImpl(Unknown Source)

java.awt.Component.dispatchEvent(Unknown Source)

java.awt.EventQueue.dispatchEvent(Unknown Source)

java.awt.SequencedEvent.dispatch(Unknown Source)

Main$SwingEvent.dispatchEvent(Main.java:43)

Main$SwingEvent.processEvent(Main.java:62)

Main.execute(Main.java:168)

Main$1.run(Main.java:22)

java.awt.event.InvocationEvent.dispatch(Unknown Source)

java.awt.EventQueue.dispatchEvent(Unknown Source)

java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)

java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)

java.awt.EventDispatchThread.pumpEvents(Unknown Source)

java.awt.EventDispatchThread.pumpEvents(Unknown Source)

java.awt.EventDispatchThread.run(Unknown Source)

I would appreciate if someone could confirm the problem (I use Swing 6 on XP). Maybe there is a problem if a SequencedEvent is dispatched by another SequencedEvent?

I hope I could described the problem with the code above; and I hope I made no stupid errors (in my real application, Swing is completely frozen, while Swing is not in the example above).

Any ideas to solve the problem are highly appreciated.

thx & rgds, Craud

Crauda at 2007-7-12 20:17:27 > top of Java-index,Desktop,Core GUI APIs...
# 5

hi

who designed this flow? why do you need so many dialogs, when one dialog is present then why you need to bring up more? do you know how much effort JVM gets to create a peer window component? this is a bad design i would say. change your logic, or it is waste of time to work with this kind of stuff.

this is my personal opinion

regards

Aniruddha

Aniruddha-Herea at 2007-7-12 20:17:28 > top of Java-index,Desktop,Core GUI APIs...
# 6
Thanks for your reply. Please be aware that this piece of code is used to reveal a problem. Discussion of the code quality is not really helpful for me. What I'm interested in: is event dispatching not permitted; is there a bug in the code; or is this a bug in the Java implementation?
Crauda at 2007-7-12 20:17:28 > top of Java-index,Desktop,Core GUI APIs...
# 7
hiwell i am sorry if i hurt you. i was not intended to hurt any one. according to me the bug is in the code/implementation.
Aniruddha-Herea at 2007-7-12 20:17:28 > top of Java-index,Desktop,Core GUI APIs...
# 8
Thanks again for your response. You wrote, the bug is in the source code. Can you please tell me which line causes the dead lock in the Swing event dispatching thread? -- I guess you could reproduce the problem, couldn't you?
Crauda at 2007-7-12 20:17:28 > top of Java-index,Desktop,Core GUI APIs...