从EDT调用invokeAndWait

时间:2010-03-12 19:49:25

标签: java swing events awt

我的previous problem发生了问题。我在代码库中的其他地方也有代码SwingUtillities.invokeAndWait,但是当我删除它时,gui不会刷新。如果我不删除它,我得到的错误是:

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)

HumanPlayer.act中的代码是:

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();
 }

调试时线程的图像,因为屏幕不绘制: alt text http://img684.imageshack.us/img684/6669/69288941.png

堆栈的文本版本:

ui.startup.LoginScreen at localhost:51050
 -> Deamon Thread [AWT-Windows] (Running)
 -> Thread [AWT-Shutdown] (Running)
 -> Thread [AWT-EventQueue-0] (Running)
 -> Thread [DestroyJavaVM] (Running)

5 个答案:

答案 0 :(得分:7)

答案不是拨打电话

new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
来自EDT的

,使其在新的(非EDT)线程上执行,以便稍后在调用invokeAndWait时它正常运行,因为运行该命令的线程不是EDT。修改后的代码如下:

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

   });
t.start();

答案 1 :(得分:4)

invokeAndWait()旨在从非GUI线程调用。它将Runnable对象发送到GUI线程,然后执行它。

从GUI线程向自身发送Runnable对象是没有意义的。它与直接在run()对象上调用Runnable具有相同的效果。

答案 2 :(得分:1)

根据评论,一旦操作完成,您似乎没有重新绘制框架。如果你不这样做,那么屏幕只会在似乎是随机的时间更新(当另一个窗口在前面移动时,也许)。

gui.update内,我建议你做最后一行:

myFrame.repaint();

(或多或少,取决于您的具体情况)。


编辑:事实证明,实际问题是这个循环:

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

由于只有一个应用程序线程(恰好是EDT),hasPerformedAction()的结果永远不会改变(假设它是一个简单的getter)。没有其他线程可以更改该值。由于这个无限循环在EDT上,因此GUI永远不会被重新绘制;因此它锁定了。

答案 3 :(得分:1)

如果当前的调用线程已经是事件调度程序,您可以检查:

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

请注意,SwingUtilities.invokeAndWait(Runnable)只是委托给EventQueue

答案 4 :(得分:0)

使用 XChart java 库时,您可以使用以下代码在按钮单击时显示图表:

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();
            }
        });