2010-03-12 2 views
5

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

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) 
+0

У вас есть вызов 'repaint()' где угодно (например, в 'gui.update()')? –

+0

Нет, у меня есть 'validate()' – Aly

+0

'validate' полностью отличается от' repaint'. –

ответ

5

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

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

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

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

+0

Да, есть ли другой способ выполнить эту команду и ждать завершения до того, как остальная часть метода будет выполнена? – Aly

+0

Я думаю, что это уже так, как это работает - поток событий - это единственный поток, поэтому он должен завершить вызов gui.update перед тем, как продолжить. –

+0

, но gui не освежает – Aly

1

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

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

myFrame.repaint(); 

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


Edit: Как выясняется, реальная проблема заключается в этом цикле:

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

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

+0

Я пробовал это без везения, gui даже не изначально рисует; экран остается белым, а X в верхнем правом углу не убивает процесс. – Aly

+0

@Aly: Вы когда-нибудь получали что-либо, чтобы рисовать на экране в этом проекте (а потом потом меняли)? –

+0

yes Я ранее создавал новый GameInitializer из другого потока (не EDT), и gui функционировал нормально. Но теперь я попытался создать еще один JFrame, который создает GameInitializer, который теперь ломает вещи, поскольку ранее вызов 'invokeAndWait' был прекрасен (поскольку начальный поток не был EDT) – Aly

0

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

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.

Смежные вопросы