2

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

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

4

5 回答 5

8

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

于 2010-12-03T19:09:32.400 回答
3

看一下javax.swing.Timer-我认为这是您完成此操作所需要的。

编辑#1:Sun\Oracle 文档实际上建议从这里使用 Swing Timers 。

一般来说,我们建议使用 Swing 计时器而不是通用计时器来处理与 GUI 相关的任务,因为 Swing 计时器都共享相同的、预先存在的计时器线程,并且与 GUI 相关的任务会自动在事件调度线程上执行。但是,如果您不打算从计时器触摸 GUI,或者需要执行冗长的处理,则可以使用通用计时器。

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

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

于 2010-12-03T19:10:08.117 回答
2

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

您应该可以为此使用 SwingWorker。阅读 Swing 教程中关于并发的部分以获取更多信息。

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

于 2010-12-03T19:35:15.190 回答
1

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

SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    board.invalidate();
    board.setLeftMessage("Not");
    board.setRightMessage("Here");
    board.revalidate();
  }
};
于 2010-12-03T19:12:26.433 回答
1

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

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

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

于 2013-01-22T15:06:42.653 回答