如何通过点击按钮取消可能无限循环?

时间:2016-12-29 07:40:27

标签: java loops button interrupt

我试图为一个具有最小接口的小型DigitalWatch类实现某种模式(只是一种练习)。

它有2个按钮:模式按钮和增量按钮。

模式按钮有一个监听器,可以触发我的程序在" SetHours,SetMinutes,DisplayTime"之间的状态变化。 (由于模式而作为对象存在,对象在我的DigitalWatch类中调用特定的state-dependend方法)。

我的方法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();
}

但似乎这个循环处于活动状态时按钮会失去其可点击性。

所以一旦"时间计数"我坚持这种状态,我不再能够改变模式。有没有一种好方法/最佳实践来维持我的模式按钮的可点击性?

1 个答案:

答案 0 :(得分: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);
    }
}