У меня есть проблема при следовании из моей предыдущей проблемы. У меня также есть код 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)
Ответ: вместо того, чтобы делать вызов
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();
На основе комментарии, похоже, вы не перерисовываете рамку после завершения действий. Если вы этого не сделаете, то экран будет обновляться только в случайное время (возможно, когда другое окно перемещается вперед).
Внутри gui.update
я предлагаю вам сделать последнюю строку:
myFrame.repaint();
(более или менее, в зависимости от ваших обстоятельств).
Редактировать: Как оказалось, настоящая проблема заключается в следующем цикле:
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
Поскольку существует только один поток приложения (который оказывается EDT), результат hasPerformedAction ()
никогда не может измениться (при условии, что это простой получатель). Нет другого потока для изменения значения. Поскольку этот бесконечный цикл находится на EDT, графический интерфейс никогда не может быть перерисован; следовательно, он блокируется.
invokeAndWait ()
предназначен для вызова из потока без графического интерфейса пользователя. Он отправляет объект Runnable
в поток графического интерфейса пользователя, где он будет выполнен.
Нет смысла отправлять объект Runnable
из потока GUI самому себе. Это имеет тот же эффект, что и прямой вызов run ()
для объекта Runnable
.