2014-04-30 35 views
0

我创建了一个弹出窗口来显示某些东西的进度,并且它与我的下载程序正常工作,所有内容都正在更新。JProgressBar在一个线程上更新,而不是在另一个线程上更新

private void downloadFile(String link, String directory, String name) throws IOException { 
    task = new Downloader(link, directory, name); 
    task.start(); 
} 

,并在下载类:

public void run() { 
     try { 
      while ((length = is.read(b)) != -1) { 
       downloaded += length; 
       bout.write(b, 0, length); 

       int percent = (int) ((downloaded * 100)/fileLength); 

       window.modify1("Downloading " + name + ".jar"); 
       window.modify2((int) downloaded, "Progress: " + percent + "% [" + String.valueOf(downloaded).subSequence(0, String.valueOf(downloaded).length() - 1) + "kb/" + String.valueOf(fileLength).subSequence(0, String.valueOf(fileLength).length() - 1) + "kb]"); 
      } 

      is.close(); 
      bout.close(); 

      window.exit(); 

      Creator c = new Creator(directory, name); 
      c.create(); 
      this.join(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

然而,当我试图在另一个线程做的差不多了,这是行不通的。直到线程完成后才显示弹出窗口中的任何内容。

LauncherThread t = new LauncherThread(); 
    t.start(); 

    try { 
     t.join(); 
    } catch (InterruptedException e2) { 
     e2.printStackTrace(); 
    } 

,并在LauncherThread类:

public void run() {  
    window.modify1("Fetching data..."); 
    window.modify2(0, "Progress: 0% [0/10]"); 

    Main.trust(); 
    window.modify2(1, "Progress: 10% [1/10]"); 

    Main.bukkitVersions = Finder.findBukkitVersions(); 
    window.modify2(2, "Progress: 20% [2/10]"); 

    Main.spigotVersions = Finder.findSpigotVersions(); 
    window.modify2(3, "Progress: 30% [3/10]"); 

    Main.vanillaVersion = Finder.findVanillaVersion(); 
    window.modify2(4, "Progress: 40% [4/10]"); 

    Main.bukkitLinks = new String[3]; 
    Main.bukkitLinks[0] = Finder.findDownloadLink("bukkit", "rb"); 
    window.modify2(5, "Progress: 50% [5/10]"); 

    Main.bukkitLinks[1] = Finder.findDownloadLink("bukkit", "beta"); 
    window.modify2(6, "Progress: 60% [6/10]"); 

    Main.bukkitLinks[2] = Finder.findDownloadLink("bukkit", "dev"); 
    window.modify2(7, "Progress: 70% [7/10]"); 

    Main.spigotLinks = new String[2]; 
    Main.spigotLinks[0] = Finder.findDownloadLink("spigot", "lastStable"); 
    window.modify2(8, "Progress: 80% [8/10]"); 

    Main.spigotLinks[1] = Finder.findDownloadLink("spigot", "lastBuild"); 
    window.modify2(9, "Progress: 90% [9/10]"); 

    Main.vanillaLink = Finder.findDownloadLink("vanilla", null); 
    window.modify2(10, "Progress: 100% [10/10]"); 

    window.exit(); 
} 

我还是很新的Java的,所以我为我的无知道歉。

编辑:我在SwingUtilities.invokeLater()中封装了t.start()方法,现在它可以工作。但新问题是主类不再等待LauncherThread完成。

回答

0

我用简单的(也可能是坏的)方式去了。初始化方法在完成后在LauncherThread中调用。

/** 
* Launch the application. 
*/ 
public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      try { 
       new Main(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

/** 
* Create the application. 
*/ 
public Main() { 
    launch(); 
} 

/** 
* Run launcher. 
*/ 
private void launch() { 
    LauncherThread t = new LauncherThread(this); 
    t.start(); 
} 

我通过它的构造函数传递主实例的LauncherThread类,所以我可以调用从那里初始化方法,而不必使用静态访问。

main.initialize(); 
0

您在遇到严重问题的过程中,我怕你当前的解决方案没有解决问题,但只是隐藏它。

根本问题是Swing(与大多数可比较的库)不是线程安全的。因此只能有一个访问Swing组件的线程。该线程不是任意的,而是一个名为EDT(Event Dispatch Thread)的特殊线程。

的那后果是:

  • UI的初始化必须包装到SwingUtilities.invokeLater来电或SwingUtilities.invokeAndWait

  • 如果你在一个单独的线程做的工作,代码不能直接触摸你的Progressbar。相反,它必须通过上述两种方法将更新发送到进度条。

如果你现在不这样做的权利,你的代码接缝的工作,但这并不意味着它会工作,明天,或者在不同的机器上,或天气变化时或在中国改变政府。

如果你想要一个线程在另一个线程上等待,你应该看看像CountDownLatch这样的东西,只要确保你不阻止EDT,因为当它被阻塞的时候,什么都不会在UI中画出来,所以应用程序似乎为用户死亡。再次通过invokeLater执行一些代码可能会解决这个问题。

0

当我不得不从另一个线程更新Swing组件,那么我从的Javadoc OT方法做它

SwingUtilites.invokeLater(new Runnable() { 
    //set new values 
}); 

Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI. 

一两件事,。 你可能会考虑通过SwingWorker来完成你的申请,那些对象很友善,EDT。但请记住,它们在有限的ThreadPool中执行。我尝试过一次推出50多名秋千工人来更新面板的组件,但是它只为其中的前10个工作。大概可以改变,让他们都跑,但我已经改变了我的方法。