我试图为一个具有最小接口的小型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();
}
但似乎这个循环处于活动状态时按钮会失去其可点击性。
所以一旦"时间计数"我坚持这种状态,我不再能够改变模式。有没有一种好方法/最佳实践来维持我的模式按钮的可点击性?
答案 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);
}
}