2014-10-01 76 views
0

我有一個TableView與一些數據相關聯,一旦我點擊運行按鈕,我對該數據執行一些處理。每行數據都在一個單獨的線程中處理,並且這些線程正在運行時,我希望ProgressInducator可以替換其vbox​​中的表。用VBox中的ProgressIndicator替換TableView JavaFX

在所附的代碼:

如果我把車子停在是說「工作,如果停在這裏」 - 表被替換爲圓周率。 如果我繼續等待線程加入 - 無需替換。 我錯過了什麼?

runButton.setOnAction(
       new EventHandler<ActionEvent>() { 
        @Override 
        public void handle(final ActionEvent e) { 
         List<Thread> threadList = new ArrayList<Thread>(); 

         int threadCounter = 0; 
         final ProgressIndicator pi = new ProgressIndicator(threadCounter); 

         vbox.getChildren().clear(); 
         vbox.getChildren().addAll(pi); 
         for (ProductInTable product : data) { 
          Thread thread = new Thread(new Runnable() { 
           @Override 
           public void run() { 
            try 
            { 
             product.calculate(); 
            } catch (IOException ioe) { 
             ioe.printStackTrace(); 
            } 
           } 
          }); 
          threadList.add(thread); 
          thread.start(); 
         } 

         int x = threadList.size(); 

         /** WORKS IF STOP HERE **/ 

         // wait for all threads to end 
         for (Thread t : threadList) { 
          try { 
           t.join(); 
           threadCounter++; 
           pi.setProgress(threadCounter/x); 
          } catch (InterruptedException interE) { 
           interE.printStackTrace(); 
          } 
         } 

         /** DOESNT WORKS IF STOP HERE **/ 

回答

0

Thread.join()阻止執行,直到線程完成。由於您在FX應用程序線程中調用了該線程,因此您將阻止該線程,直到所有工作線程完成。這意味着用戶界面無法更新,直到這些線程完成。

更好的方法可能是用任務表示每個計算,並使用setOnSucceeded在FX應用程序線程上更新完整任務的計數器。喜歡的東西:

runButton.setOnAction(
      new EventHandler<ActionEvent>() { 
       @Override 
       public void handle(final ActionEvent e) { 

        final ProgressIndicator pi = new ProgressIndicator(threadCounter); 

        vbox.getChildren().clear(); 
        vbox.getChildren().addAll(pi); 

        final int numTasks = data.size(); 

        // only access from FX Application thread: 
        final IntegerProperty completedTaskCount = new SimpleIntegerProperty(0); 

        pi.progressProperty().bind(completedTaskCount.divide(1.0*numTasks)); 

        completedTaskCount.addListener(new ChangeListener<Number>() { 
         @Override 
         public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) { 
          if (newValue.intValue() >= numTasks) { 
           // hide progress indicator and show table.. 
          } 
         } 
        }); 

        for (final ProductInTable product : data) { 
         Task<Void> task = new Task<Void>() { 
          @Override 
          public Void call() { 
           try 
           { 
            product.calculate(); 
           } catch (IOException ioe) { 
            ioe.printStackTrace(); 
           } 
           return null ; 
          } 
         }); 
         task.setOnSucceeded(new EventHandler<WorkerStateEvent>() { 
          @Override 
          public void handle(WorkerStateEvent event) { 
           completedTaskCount.set(completedTaskCount.get()+1); 
          } 
         }); 
         new Thread(task).start(); 
        } 

       } 
}); 

如果你可能有大量的項目在這裏,你應該使用某種ExecutorService來避免產生過多的線程:

ExecutorService exec = Executors.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors()); // for example... 

,然後更換

new Thread(task).start(); 

exec.submit(task); 
+0

有多少線程太多? – sinai 2014-10-07 10:40:30

+0

這取決於平臺,我對這個問題沒有很好的答案。我想我總是儘量保持在與系統上的處理器數量相同的數量級上;但我不確定這是否是一項好的政策。如果您有疑問,我建議使用'ExecutorService'來管理日程安排。 – 2014-10-07 12:52:36