从 EDT 调用 invokeAndWait

发布于 2024-08-24 18:35:16 字数 1635 浏览 10 评论 0原文

我在上一个问题之后遇到了问题。我在代码库的其他地方也有代码 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();
 }

调试时线程的图像,因为屏幕不绘制: 替代文本 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)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

谈情不如逗狗 2024-08-31 18:35:16

答案是不要从 EDT 进行调用

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

,而是让它在新的(非 EDT)线程上执行,以便稍后调用 invokeAndWait 时,它的功能与运行该命令的线程一样正确,而不是美东时间。修改后的代码如下:

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

   });
t.start();

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();
凉风有信 2024-08-31 18:35:16

invokeAndWait() 旨在从非 GUI 线程调用。它将一个 Runnable 对象发送到将在其中执行的 GUI 线程。

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

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.

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

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

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.

¢好甜 2024-08-31 18:35:16

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

gui.update 中,我建议您添加最后一行:(

myFrame.repaint();

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


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

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

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

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.

聽兲甴掵 2024-08-31 18:35:16

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

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();
            }
        });
染年凉城似染瑾 2024-08-31 18:35:16

尝试从此执行您的代码

Executors.newSingleThreadExecutor().execute(new Runnable() {
                     public void run() {

                     }
                   });
                
    

try to execute your code from this

Executors.newSingleThreadExecutor().execute(new Runnable() {
                     public void run() {

                     }
                   });
                
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文