вызов invokeAndWait из EDT - PullRequest
       25

вызов invokeAndWait из EDT

6 голосов
/ 12 марта 2010

У меня проблема, следующая из моей предыдущей проблемы . У меня также есть код SwingUtillities.invokeAndWait где-то еще в базе кода, но когда я удаляю это, графический интерфейс не обновляется. Если я не удаляю это, я получаю ошибку:

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)

Ответы [ 4 ]

7 голосов
/ 13 марта 2010

Ответ был вместо того, чтобы сделать звонок

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();
4 голосов
/ 12 марта 2010

invokeAndWait() предназначен для вызова из потока без графического интерфейса. Он отправляет объект Runnable в поток GUI, где он будет выполняться.

Нет смысла отправлять объект Runnable из GUI-потока самому себе. Он имеет тот же эффект, что и непосредственный вызов run() для объекта Runnable.

1 голос
/ 19 марта 2017

Ранее вы можете проверить, является ли ваш текущий вызывающий поток уже диспетчером событий:

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.

1 голос
/ 12 марта 2010

Судя по комментариям, вы не перекрашиваете фрейм после завершения действий. Если вы этого не сделаете, то экран будет обновляться только в то время, которое кажется случайным (когда, возможно, впереди другое окно).

Внутри gui.update, я предлагаю вам сделать последнюю строку:

myFrame.repaint();

(более или менее, в зависимости от ваших обстоятельств).


Редактировать: Как оказалось, настоящей проблемой является этот цикл:

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

Поскольку существует только один поток приложения (который является EDT), результат hasPerformedAction() никогда не может измениться (при условии, что это простой метод получения). Нет другого потока для изменения значения. Поскольку этот бесконечный цикл находится на EDT, GUI никогда не может быть перекрашен; следовательно, он блокируется.

...