Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling invokeAndWait from the EDT

I have a problem following from my previous problem. I also have the code SwingUtillities.invokeAndWait somewhere else in the code base, but when I remove this the gui does not refresh. If I dont remove it the error I get is:

Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
 at java.awt.EventQueue.invokeAndWait(Unknown Source)
 at javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
 at game.player.humanplayer.model.HumanPlayer.act(HumanPlayer.java:69)

The code in HumanPlayer.act is:

public Action act(final Action[] availiableActions) {
  try {

   SwingUtilities.invokeAndWait(new Runnable() {
    @Override
    public void run() {
     gui.update(availiableActions);
    }
   });
  }
  catch (InterruptedException e) {
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   e.printStackTrace();
  }

  synchronized(performedAction){
   while(!hasPerformedAction()){
    try {
     performedAction.wait();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   setPerformedAction(false); 
  }

  return getActionPerfomed();
 }

Image of threads when in debug as screen doesn't paint: alt text http://img684.imageshack.us/img684/6669/69288941.png

Text version of stack:

ui.startup.LoginScreen at localhost:51050
 -> Deamon Thread [AWT-Windows] (Running)
 -> Thread [AWT-Shutdown] (Running)
 -> Thread [AWT-EventQueue-0] (Running)
 -> Thread [DestroyJavaVM] (Running)
like image 781
Aly Avatar asked Mar 12 '10 19:03

Aly


3 Answers

The answer was instead of making the call

new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);

from the EDT, make it execute on a new (non EDT) thread so that later when invokeAndWait is called it functions as correctly as the thread running that command is not the EDT. The amended code is as follows:

Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
       new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);       
    }

   });
t.start();
like image 140
Aly Avatar answered Oct 14 '22 16:10

Aly


invokeAndWait() is meant to be called from the non-GUI thread. It sends a Runnable object to the GUI thread where it will be executed.

There's no point in sending a Runnable object from the GUI-thread to itself. It has the same effect as calling run() on the Runnable object directly.

like image 6
Itay Maman Avatar answered Oct 14 '22 17:10

Itay Maman


You can check before if your current calling thread is already the event dispatcher:

private void syncExec(final Runnable r) {
    try {
        if (EventQueue.isDispatchThread()) r.run();
        else EventQueue.invokeAndWait(r);
    } catch (final Exception e) {
        Throws.throwRuntime(e);
    }
}

Note that SwingUtilities.invokeAndWait(Runnable) simply delegates to the EventQueue.

like image 4
benez Avatar answered Oct 14 '22 16:10

benez