2015-09-25 45 views
1

做我有這樣的代碼:GUI卡住如果循環內EDT

Thread T=new Thread(new Runnable(){ 
    public void run(){ 
     SwingUtilities.invokeLater(new Runnable(){ 
      public void run(){ 
       for (int i=0;i<18;i++){ 
        int percent=(int)(((i+1)*100)/18); 
        try { 
         lblNewLabel.setText("Loading... ("+percent+"%)"); 
         Thread.sleep(1000); 
        } 
        catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }); 
    } 
}); 

我的問題是,我的標籤不會改變它的文本此線程盯着之後,反而會留在舊文本(在此代碼標籤上加上「加載...(0%)」文本)。 有沒有辦法避免這麼做?

然後......如果我叫了invokeLater只在我的setText調用是這樣的:

SwingUtilities.invokeLater(new Runnable(){ 

     public void run(){ 

      lblNewLabel.setText("Loading...("+percent+"%)"); 
     } 
    }); 

它會被稱爲18倍。這是一個好方法嗎?或者最好不要調用invokeLater方法那麼多次?

謝謝

+0

好像你已經使用了'爲「事件分派線程」 edt'標籤,但實際上不是什麼它是。看看[這裏](http://stackoverflow.com/tags/edt/info)。我編輯刪除它從這個問題(將在審查後可見)。 – Lii

+0

特赦,不知道。 –

回答

1

以下工作:

public class UIThreadTest { 

    private JFrame mainFrame; 
    private JLabel labelStatus; 
    private JButton buttonProcess; 

    public static void main(String[] args) { 
     final UIThreadTest ui = new UIThreadTest(); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       ui.initGUI(); 
      } 
     }); 
    } 

    public void initGUI() { 
     mainFrame = new JFrame("View"); 
     mainFrame.getContentPane().setLayout(new BorderLayout()); 
     mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     mainFrame.setSize(200, 200); 
     mainFrame.setVisible(true); 
     mainFrame.setLocationRelativeTo(null); 

     labelStatus = new JLabel("Status..."); 
     mainFrame.getContentPane().add(labelStatus, BorderLayout.NORTH); 

     buttonProcess = new JButton("Start"); 
     buttonProcess.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       Runnable startLoop = new StartLoop(); 
       Thread startLoopThread = new Thread(startLoop); 
       startLoopThread.start(); 
      } 

     }); 
     mainFrame.getContentPane().add(buttonProcess, BorderLayout.SOUTH); 
    } 

    private void updateStatus(final int val) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       labelStatus.setText("Loading... (" + val + "%)"); 
      } 
     }); 

    } 

    private void runForLoop() { 
     for (int i = 0; i < 18; i++) { 
      int percent = (int) (((i + 1) * 100)/18); 
      updateStatus(percent); 
      try { 
       Thread.sleep(1000L); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private class StartLoop implements Runnable { 
     @Override 
     public void run() { 
      runForLoop(); 
     } 

    } 
} 
+0

真的非常感謝您的幫助,我也接近這個解決方案..但是..調用這麼多次invokeLater是個好主意嗎?這會效率低下嗎?或者這樣做是個好主意?在這段代碼中,它被稱爲18次...... –

+0

我認爲它會和其他方法調用18次一樣好。 invokeLater文檔說:「導致doRun.run()在AWT事件派發線程上異步執行,這將在處理完所有未處理的AWT事件後發生。」你爲什麼認爲這可能是低效率的?「我們也沒有阻止美國東部時間。你可能也喜歡[link](http://stackoverflow.com/questions/9289331/edt-and-other-thread-relations-regard-重繪-方法-java的) –