2016-12-29 4 views
1

Я пытаюсь реализовать определенный шаблон для небольшого класса DigitalWatch с минимальным интерфейсом в java (просто практика).Как отменить потенциально бесконечный цикл нажатием кнопки?

У этого есть 2 кнопки: кнопка режима и кнопка приращения.

Кнопка режима имеет прослушиватель, который запускает изменение состояния моей программы между «SetHours, SetMinutes, DisplayTime» (которые существуют как объекты из-за шаблона, объекты вызывают определенные методы зависимости состояния в моем классе DigitalWatch) ,

Мой метод displayTime() что-то вроде этого:

void displayTime() 
{ 
    while (pressed==false) 
    { 
     try 
     { 
      display.setText(String.format("%02d:%02d", hours, minutes)); 
      display.repaint(); 
      Thread.sleep(1000); 
      minutes = minutes + 1; 
      if (minutes > 59) 
      { 
       minutes = 0; 
       hours = hours + 1; 
      } 
      if (hours > 23) 
      { 
       hours = 0; 
      } 
      display.setText(String.format("%02d:%02d", hours, minutes)); 
      display.repaint(); 
     } catch (Exception e) 
     { 
      break; 
     } 
    } 
    display.setText(String.format("%02d:%02d", hours, minutes)); 
    display.repaint(); 
} 

Но, кажется, что в то время как этот цикл активен кнопка теряет свою кликабельность.

Итак, как только «время отсчитывается», я застрял в этом состоянии и больше не могу изменить режим. Есть ли хороший способ/передовая практика для поддержания кликабельности моего режима?

+0

Возможный дубликат [свинг GUI Предотвращение блокировки во время фоновой задачи] (http://stackoverflow.com/questions/940913/prevent-swing-gui-locking-up -during-a-background-task) – Raniz

+0

Вы блокируете поток отправки событий. То есть ваш поток gui. Вам нужно поместить этот код в отдельный поток. Однако обновление элементов gui должно выполняться на edt. Поэтому вам нужно разделить это. – Fildor

+0

Это приводит меня к, вероятно, глупому вопросу: где же это в моем случае? – Wolfone

ответ

1

В Swing все события отправляются по одному потоку, и поскольку ваш цикл никогда не выходит из него, он блокирует поток пользовательского интерфейса и предотвращает обработку любых будущих событий.

Что вам нужно сделать, это выполнить цикл в отдельном потоке и управлять состоянием этого потока с помощью кнопки. Нам также необходимо убедиться, что мы запускаем любой UI-код в UI-потоке, поэтому вам нужно будет переключаться между потоком таймера и потоком пользовательского интерфейса.

Поскольку вы выполняете повторяющуюся задачу каждую секунду, ScheduledExecutorService.scheduledAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) подходит.

Что-то вроде этого:

private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); 
private ScheduledFuture<?> timerFuture = null; 

void toggleTimer() 
{ 
    if (timerFuture != null) 
    { 
     // Stop the timer 
     timerFuture.cancel(); 
     timerFuture = null; 
    } else 
    { 
     // Start the timer on the separate thread, run it every second 
     timerFuture = executor.scheduleAtFixedRate((Runnable)() -> { 
      minutes = minutes + 1; 
      if (minutes > 59) 
      { 
       minutes = 0; 
       hours = hours + 1; 
      } 
      if (hours > 23) 
      { 
       hours = 0; 
      } 
      // Update the UI, this needs to be done on the UI thread 
      SwingUtilities.invokeLater(() -> { 
       display.setText(String.format("%02d:%02d", hours, minutes)); 
       display.repaint(); 
      }); 
     }, 0, 1, TimeUnit.SECONDS); 
    } 
} 
+0

Спасибо за ваш быстрый ответ! Это кажется очень сложным, и, честно говоря, мне нужно некоторое время, чтобы понять, что действительно происходит внизу (я новичок). Я нашел что-то похожее на мою ситуацию здесь: http://stackoverflow.com/questions/12821220/how-to-stop-a-loop-with-a-button?rq=1 И поскольку я не знаком с нити я не уверен в различии. Я думаю, что потоки в вашем ответе создаются «под пальто» по «scheduleAtFixedRate», можете ли вы объяснить качественное различие во втором ответе в упомянутом сообщении? (с изменчивой переменной) – Wolfone

+0

Да, ваша проблема такая же, как и в связанном с вами вопросе (вы можете подумать о том, чтобы отметить этот вопрос как дубликат этого). Разница в ответах заключается в том, что служба-исполнитель обрабатывает поток (-ы) для вас, поэтому вам нужно только подумать о задачах (Runnables/lambdas, ScheduledFuture), а не управлять, запускать или останавливать потоки. – Raniz

+0

Хорошо, спасибо; знаете ли вы наизусть, если в вашем ответе есть летучие вещества, используемые под капотом? – Wolfone