Thread.sleep和重新绘制
我有一个显示文本的面板。 我希望面板更改其文本,然后在其他任何事情发生之前暂停应用程序。 我正在使用Thread.sleep(1000)。 但是,出于某种原因,应用程序在调用Thread.sleep之前没有完成绘制面板(文本没有被更改)。 我也试过这个:
board.invalidate(); board.setLeftMessage("Not"); board.setRightMessage("Here"); board.revalidate(); Date current = new Date(); long timeNow = current.getTime(); Date newDate = new Date(timeNow + 1000); while (current.before(newDate)) current = new Date();
但也没有运气。 有人有建议吗? 非常感谢。
您正在阻止AWT事件调度线程(EDT)。 EDT处理重新绘制和输入事件,因此您的代码不需要multithreading(这实际上是不可能的)。 使用javax.swing.Timer
稍后在EDT上发送事件。 (不要将javax.swing.Timer
与java.util.Timer
混淆!)
看看javax.swing.Timer
– 我认为这是你需要完成的。
编辑#1:Sun \ Oracle文档实际上建议使用Swing Timers。
通常,我们建议使用Swing计时器而不是通用计时器来处理与GUI相关的任务,因为Swing计时器都共享相同的预先存在的计时器线程,并且GUI相关任务会自动在事件派发线程上执行。 但是,如果您不打算从计时器触摸GUI,或者需要执行冗长的处理,则可以使用通用计时器。
编辑#2:看起来这里有一些很好的基础教程。
编辑#3:删除了使用TimerTask的建议 – 在这种情况下,这将是一个坏主意。
您的“长时间运行的任务”需要在单独的线程中运行。 然后,当您想要更新GUI时,您需要在Event Dispatch Thread(EDT)上运行代码。 然后你可以让单独的Threadhibernate,它不会影响GUI的绘制。
您应该可以使用SwingWorker。 有关更多信息,请阅读Swing教程中的并发部分。
如果您不喜欢使用SwingWorker,那么您需要创建自己的Thread并在SwingUtilities.invokeLater()中包装更新GUI的代码。
您不应该从主线程更新GUI组件。 使用SwingUtilities.invokeLater
在事件线程上安排更新:
SwingUtilities.invokeLater(new Runnable() { public void run() { board.invalidate(); board.setLeftMessage("Not"); board.setRightMessage("Here"); board.revalidate(); } };
Thread.sleep
是一个长期运行的任务。 当您在EDT中运行此类任务时,它会阻止执行所有重绘请求。 所有待处理的重绘请求和在睡眠阶段期间发送的所有重新绘制请求都排队等待将来处理。
因此,当EDT退出sleep
阶段时,它会将所有这样的重绘请求(如果启用了合并,这是默认属性)合并为一个重新执行,这将被执行。 如果未启用合并,则所有排队的请求将按顺序执行,两者之间没有任何时间间隔。 结果似乎UI没有更新。
要纠正这种情况,请使用timer
,该timer
在特定时间间隔后定期触发。