2012-02-29 3 views
0

Я пытаюсь закодировать простую игру на Java. Базовая структура - это один JFrame с различными JPanels, которые я добавляю/удаляю в разное время. При запуске есть JPanel, это основное меню (стартовая игра, высокие баллы и т. Д.). Как только кнопка «Старт» нажата, она переключается на панель выбора уровня с тремя кнопками, чтобы выбрать сложный уровень игры. Как только какая-либо из трех кнопок нажата, она переключается на другую панель, на которой будет отображаться три секунды обратного отсчета, а затем фактическая игра. Все три кнопки вызывают один и тот же метод, только с другой переданной ошибкой.GUI threading in java

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

С точки зрения кода, на панели выбора уровня у меня есть что-то вроде этого прослушивания для нажатия кнопок:

private class ButtonClickedListener implements ActionListener { 
    public void actionPerformed(ActionEvent evt) { 
     gui.newLevel(1); 
    } 
} 

где вместо всего gui.newLevel(1) я возился с началом новых потоков и вызова метода от них.

newLevel() метод выглядит следующим образом:

getContentPane().removeAll(); 

levelPanel = new LevelPanel(levelNum, this); 
add(levelPanel); 
validate(); 

levelPanel.start(); 

Я использую очень похожий код при переключении из стартового меню JPanel на панель селектора уровня (опять же, с ActionListener на кнопках), который работает просто отлично.

start() метод LevelPanel инициализирует значения для нового JPanel и отображает отсчет времени на экране (в настоящее время со следующим кодом, хотя я перепутались с проставлением что-то вроде этого в методе newLevel() вместо этого) перед отображением фактической игры:

try { 
    Thread.sleep(1000); 
    //update countdown number 
    validate(); 
    repaint(); 
    Thread.sleep(1000); 
    //update countdown number 
    validate(); 
    repaint(); 
    Thread.sleep(1000); 
    //update countdown number 
    validate(); 
    repaint(); 
} catch (Exception e) { 
    System.out.println(e); 
} 

//start game 

Я был бы очень признателен за любую помощь в работе этого кода, и я уверен, что какой-то поток - это путь, но я не совсем уверен, где и как. Любые предложения и/или образцы кода были бы замечательными!

Заранее спасибо!

EDIT: я в конечном итоге переписывание отсчетого времени с использованием таймера вместо Thread.sleep(), который неподвижной части проблемы и остальной частью этого я в конце концов понял, и был совершенно не связан с GUI вещей, поэтому я Жду» Подумайте, чтобы проверить это в первую очередь.

ответ

5

Макет и покраска должны быть выполнены в формате EDT.Используйте SwingUtilities.invokeAndWait для вызова validate() и repaint()

+0

Можете ли вы привести пример кода, как это будет работать? – scaevity

+0

также, где конкретно в моем коде следует использовать invokeAndWait()? – scaevity

+0

'invokeAndWait' имеет тенденцию приводить к взаимоблокировкам. 'invokeLater', как правило, намного лучше. –

6

никогда не никогда не использовать Thread.sleep(1000); во время EDT, этот код вызвал замораживание GUI является un_resposible, до тех пор пока новое событие Invoke EDT или мыши парят над банкой жив этот контейнер слишком

1) есть два способа, как Дили любого события (ы) в GUI Swing, по инвентарю

  • Swing Timer

  • задержки с помощью Thread.sleep(1000); в SwingWorker

+0

Можете ли вы привести пример с одним (или обоими) из них (с кодом)? Я не использовал Swing Timer, и мои попытки заставить SwingWorker работать до сих пор не очень успешны. – scaevity

+1

@scae [Swing Timer] (http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) ---> [мои сообщения здесь] (http://stackoverflow.com/search? tab = newest & q = user% 3a714968% 20timer) и [SwingWorker] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html) ---> [мои сообщения здесь] (http: /stackoverflow.com/search?tab=newest&q=user%3a714968%20swingworker) – mKorbel

0

Вы можете начать некоторый код с задержкой по времени с помощью TimerTask:

Timer timer = new Timer(); 
timer.schedule(new TimerTask() { 
    public void run() { 
     invokeLater(); // This starts after [delay] ms 
     // and - if given - will run every [period] ms. 
    } 
}, delay, period); 

Вы могли бы решить вашу проблему с этим, хотя это не будет довольно решение ,

// edit: (см. Комментарии), вы должны правильно синхронизировать обращения к gui, иначе это даст вам ошибки.

+1

отредактируйте свое сообщение и заверните 'doSomething();' в 'invokeLater()', иначе вы можете ожидать несколько down_votes до вашего действительно неправильного ответа, который вызывая тем же (как OP) вопрос. – mKorbel

+1

* «это не будет довольно хорошим решением». * Это не будет решением вообще, если обновления GUI не будут выполнены на EDT. Именно здесь пригодится ['javax.swing.Timer'] (http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html) и' SwingWorker'. –

+0

@mKorbel Ударь меня! Правильный ответ и правильный комментарий. :) –