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 thr开发者_如何学Ceads 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)
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();
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.
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
.
Based on the comments, it appears you are not repainting the frame once the actions are completed. If you do not, then the screen will only be updated at what seems to be random times (when another window moves in front, perhaps).
Inside gui.update
, I suggest you make the last line:
myFrame.repaint();
(more or less, depending on your circumstances).
Edit: As it turns out, the actual problem is this loop:
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
Since there is only one application thread (which happens to be the EDT), the result of hasPerformedAction()
can never change (assuming it's a simple getter). There is no other thread to change the value. Since this infinite loop is on the EDT, the GUI can never be repainted; hence it locks up.
When using XChart java library you can show your chart on button click with this code:
JButton btn = new JButton("View chart");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
new SwingWrapper(yourChart).displayChart();
}
});
t.start();
}
});
try to execute your code from this
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
}
});
精彩评论