2014-04-30 60 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個工作。大概可以改變,讓他們都跑,但我已經改變了我的方法。