2016-12-29 73 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

[防止Swing GUI的后台任务期间锁定了(可能的重复http://stackoverflow.com/questions/940913/prevent-swing-gui-locking-up -during-a-background-task) – Raniz

+0

您正在阻止您的Event调度线程。即你的gui线程。您需要将该代码放在单独的线程中。更新gui元素应该在edt上完成。所以你需要把它分开。 – Fildor

+0

这让我想到了一个可能很愚蠢的问题:我的案例edt在哪里? – Wolfone

回答

1

在Swing中,所有事件都在单个线程上调度,并且由于循环永远不会退出,所以会阻塞UI线程并阻止处理任何未来事件。

你需要做的是在一个单独的线程中执行你的循环,并用按钮控制该线程的状态。我们还需要确保我们在UI线程上运行任何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