Thread.sleep和重新绘制

时间:2010-12-03 19:07:11

标签: java multithreading swing repaint

我有一个显示文字的面板。我希望面板更改其文本,然后在其他任何事情发生之前暂停应用程序。我正在使用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();

但也没有运气。有人有建议吗? 非常感谢。

5 个答案:

答案 0 :(得分:8)

您正在阻止AWT事件调度线程(EDT)。 EDT处理重新绘制和输入事件,因此您的代码不需要多线程(这实际上是不可能的)。使用javax.swing.Timer稍后在EDT上发送活动。 (不要将javax.swing.Timerjava.util.Timer混淆!)

答案 1 :(得分:3)

看看javax.swing.Timer - 我认为这就是你需要做到的。

编辑#1:Sun \ Oracle文档实际上建议使用来自here的Swing Timers。

  

一般情况下,我们建议使用Swing   定时器而不是通用的   GUI相关任务的计时器,因为   摆动计时器都有相同的,   预先存在的计时器线程和   与GUI相关的任务自动完成   在事件派发线程上执行。   但是,您可以使用   通用计时器,如果你不这样做   计划从触摸GUI   计时器,或需要执行冗长   处理

编辑#2:看起来有一些很好的基础教程here

编辑#3:删除了使用TimerTask的建议 - 在这种情况下,这将是一个坏主意。

答案 2 :(得分:2)

您的“长时间运行的任务”需要在单独的线程中运行。然后,当您想要更新GUI时,您需要在Event Dispatch Thread(EDT)上运行代码。然后你可以让单独的Thread休眠,它不会影响GUI的绘制。

您应该能够使用SwingWorker。有关详细信息,请阅读Concurrency上的Swing教程中的部分。

如果您不喜欢使用SwingWorker,那么您需要创建自己的Thread并在SwingUtilities.invokeLater()中包装更新GUI的代码。

答案 3 :(得分:1)

您不应该从主线程更新GUI组件。使用SwingUtilities.invokeLater在事件线程上安排更新:

SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    board.invalidate();
    board.setLeftMessage("Not");
    board.setRightMessage("Here");
    board.revalidate();
  }
};

答案 4 :(得分:1)

Thread.sleep是一项长期任务。当您在EDT中运行此类任务时,它会阻止执行所有重新绘制请求。所有待处理的重绘请求和在睡眠阶段发送的重新排序请求都会排队等待以后处理。

结果,当EDT退出sleep阶段时,它将所有这样的重绘请求(如果启用了合并,这是默认属性)合并为一个重新执行的执行。如果未启用合并,则所有排队的请求将按顺序执行,两者之间没有任何时间间隔。结果似乎UI没有更新。

要纠正这种情况,请使用timer,它会在特定的时间间隔后定期触发。