0

我是 Java 和一般线程的新手,我在 Java 中有以下 GUI 应用程序:

  1. 在一个框架中,用户在任意位置单击鼠标,就会出现一个图像。

  2. 图像出现后,实时计时器开始运行,jLabel 根据用户在 gui 上选择的值进行自我更新,该计时器最多可以运行 5 秒。

  3. 同时播放声音片段。如果图像和声音匹配,用户点击并因此停止计时器。更新了几个 jLabel 值以反映匹配或未命中。如果不是,则用户处于空闲状态,并在计时器用完后等待图像/声音剪辑对更改。如果任一用户停止定时器或定时器用完,应用程序等待图像间时间段的预选值并转到下一个图像/声音值。

我有以下结构:

我打电话

while(true)
{
SwingUtilities.invokeAndWait(displayTimer);
}

在我的run()方法中。

Runnable的是

private final Runnable displayTimer= new Runnable()
{
public void run()
{
 displayElapsed(System.currentTimeMillis() - startTime);
}

};

稍后初始化并startTime作为任务开始的起始参考点。

我的displayElapsed()方法很混乱,检查计时器是否通过用户输入或不活动停止。如果不是,则更新jLabel计时器的负责人。如果是这样,它会调用一个startInteraction()方法。

startInteraction()准备新的图像和声音,分别显示和播放,创建一个新线程updater并启动它。

我也有一个mouseListener监听用户输入的。它调用updater.interrupt()用户点击。

现在,问题。我知道swing是线程不安全的。这种行为肯定会出现问题,因为有时它不会立即响应用户的鼠标点击,有时会在没有适当等待量的情况下通过两个图像/声音对。标签也不会立即更新。

总的来说,结构看起来很乱,我无法从逻辑上真正解释。

我所知道的是,我每次displayElapsed做的事情都会启动一个新线程,并且每次有用户或空闲停止时我都会中断它。所以从技术上讲,每个线程应该是按顺序排列的。

必须有更好的方法来做到这一点,我想看看重写这个方法是一个好的开始。

4

1 回答 1

2

看看这篇关于SwingWorker的文章。您的程序遇到的问题是事件调度线程(这是用于呈现用户界面的唯一线程)被无限循环阻塞,因为可运行对象在 EDT 中同步执行。

您想要的是在不同的线程中运行您的计时器代码,并在此线程中发布定期任务以更新 EDT 中的标签。SwingWorker 类将帮助您完成此任务。为此,您

  1. 子类化(或创建匿名)SwingWorker
  2. 实现doInBackground你的定时循环
  3. 在计时循环中,调用publish以传递时间戳(或您想要放入标签中的任何内容)
  4. 实施process更新标签
  5. 实例化工人并调用run.
于 2012-09-28T08:10:24.243 回答