【问题标题】:Thread.sleep and repaintingThread.sleep 和重绘
【发布时间】:2010-12-03 19:07:10
【问题描述】:

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

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

【问题讨论】:

  • 永远不要阻塞主线程。

标签: java multithreading swing repaint


【解决方案1】:

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

【讨论】:

  • 哇——尽管你说——“不要混淆”我还是设法做到了。应该把那个加粗;)
  • @javamonkey79 在看到您的回答后,我实际上添加了该位。 (Stack Overflow 提供了一个五分钟的窗口,其中编辑不会出现在历史记录中。)
【解决方案2】:

看看javax.swing.Timer - 我认为这是您完成此任务所需要的。

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

一般来说,我们建议使用 Swing 计时器而不是通用的 GUI 相关任务的计时器,因为 摆动计时器都共享相同的, 预先存在的计时器线程和 GUI相关任务自动 在事件调度线程上执行。 但是,您可以使用 通用定时器,如果你不这样做 计划从 计时器,或需要长时间执行 处理。

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

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

【讨论】:

  • 如果您使用TimerTask,您将离开美国东部时间,因此处于危险之中。
  • @Tom - 怎么样?你能详细说明一下吗?
  • 谢谢。是的,我试过 TimerTask 也没有运气。但是我怎样才能在摇摆计时器中安排暂停呢?我可以在 actionPerformed 方法中放入什么来使程序停止?如果我延迟安排任务,程序的其余部分仍将继续运行。
  • @rach 你把延迟后要执行的所有代码都放在actionPerformed实现中。
【解决方案3】:

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

您应该可以为此使用 SwingWorker。阅读 Concurrency 上的 Swing 教程部分了解更多信息。

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 但是你不能真的把它设置为间隔运行,对吧?
    • @javamonkey79:这仅用于 GUI 更新。在此之后,OP 仍然可以使用Thread.sleep
    【解决方案5】:

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

    因此,当 EDT 退出 sleep 阶段时,它会将所有此类重绘请求(如果启用了默认属性的合并)合并为一个执行的重绘。如果未启用合并,则所有排队的请求都将连续执行,中间没有任何时间间隔。结果似乎 UI 没有更新。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 2021-09-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多