2012-02-06 84 views
9

我想在TilePane中加載最多九個面板。對於每個窗格,我必須首先運行內容計算(大約300ms),其次是構建面板(大約500ms)。我想要的是,有9個ProgressIndicators在計算後與每個面板進行交換。 我使用Platform.runlater命令以及服務類來試用它。結果總是一樣的。 ProgressIndicator顯示,但不是動畫。幾秒鐘後,所有的面板一次。 有沒有可能,指標是動畫空洞時間,我可以一個接一個地交換它們?JavaFX在後臺執行任務

回答

11

JavaFX有用於UI事件的Event Dispatch Thread。所有使用UI的工作都應該發生在這個線程上。非UI計算不應該發生在那裏以避免UI中的滯後。

見下面的代碼:

public class Indicators extends Application { 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage stage) { 
     Pane root = new HBox(); 
     stage.setScene(new Scene(root, 300, 100)); 

     for (int i = 0; i < 10; i++) { 
      final ProgressIndicator pi = new ProgressIndicator(0); 
      root.getChildren().add(pi); 

      // separate non-FX thread 
      new Thread() { 

       // runnable for that thread 
       public void run() { 
        for (int i = 0; i < 20; i++) { 
         try { 
          // imitating work 
          Thread.sleep(new Random().nextInt(1000)); 
         } catch (InterruptedException ex) { 
          ex.printStackTrace(); 
         } 
         final double progress = i*0.05; 
         // update ProgressIndicator on FX thread 
         Platform.runLater(new Runnable() { 

          public void run() { 
           pi.setProgress(progress); 
          } 
         }); 
        } 
       } 
      }.start(); 
     } 

     stage.show(); 

    } 
} 
+0

喜謝爾蓋......我有一個問題,我可以有幾個在應用程序中運行這些線程?謝謝。 – 2015-06-22 15:24:36

+1

@MarcoR,當然,你可以多次運行'new Thread()'。 – 2015-06-22 16:27:18

+0

謝謝謝爾蓋,建議在應用程序中有幾個Platform.runLater ??。由於這些線程必須更改視圖,以檢查是否顯示對話框。 – 2015-06-22 16:47:59

12

這是我如何解決了這個問題:

import java.util.Random; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.concurrent.Service; 
import javafx.concurrent.Task; 
import javafx.concurrent.Worker; 
import javafx.concurrent.Worker.State; 
import javafx.geometry.Insets; 
import javafx.scene.Group; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.control.ProgressBar; 
import javafx.scene.control.ProgressIndicator; 
import javafx.scene.layout.StackPane; 
import javafx.scene.layout.TilePane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 


public class Minimal extends Application { 

private TilePane loadPane; 
private ProgressIndicator[] indicators = new ProgressIndicator[9]; 
private Label loading[] = new Label[9]; 
private Color[] colors = {Color.BLACK,Color.BLUE,Color.CRIMSON,Color.DARKCYAN,Color.FORESTGREEN,Color.GOLD,Color.HOTPINK,Color.INDIGO,Color.KHAKI}; 
private int counter = 0; 

@Override 
public void start(Stage primaryStage) throws Exception { 
    //creating Layout 
    final Group root = new Group();        
    Scene scene = new Scene(root, 400, 400);    
    primaryStage.setScene(scene); 
    primaryStage.setResizable(false); 
    StackPane waitingPane = new StackPane(); 
    final ProgressBar progress = new ProgressBar(); 
    Label load = new Label("loading things..."); 
    progress.setTranslateY(-25); 
    load.setTranslateY(25); 
    waitingPane.getChildren().addAll(new Rectangle(400,400,Color.WHITE),load,progress); 
    root.getChildren().add(waitingPane); 

    //Task for computing the Panels: 
    Task<Void> task = new Task<Void>() { 
     @Override 
     protected Void call() throws Exception { 
      for (int i = 0; i < 20; i++) { 
       try { 
        Thread.sleep(new Random().nextInt(1000)); 
       } catch (InterruptedException ex) { 
        ex.printStackTrace(); 
       } 
       final double prog = i*0.05; 
       Platform.runLater(new Runnable() { 
        public void run() { 
         progress.setProgress(prog); 
        } 
       }); 
      } 
      return null; 
     } 
    }; 

    //stateProperty for Task: 
    task.stateProperty().addListener(new ChangeListener<Worker.State>() { 

     @Override 
     public void changed(ObservableValue<? extends State> observable, 
       State oldValue, Worker.State newState) { 
      if(newState==Worker.State.SUCCEEDED){ 
       loadPanels(root); 
      } 
     } 
    }); 

    //start Task 
    new Thread(task).start(); 

    primaryStage.show(); 
} 

private void loadPanels(Group root) { 
    //change to loadPanel: 
    root.getChildren().set(0,createLoadPane()); 

    //Service: 
    final Service<Rectangle> RecBuilder = new Service<Rectangle>() { 
      @Override protected Task<Rectangle> createTask() { 
       return new Task<Rectangle>() { 
        @Override protected Rectangle call() throws InterruptedException { 
         updateMessage("loading rectangle . . ."); 
         updateProgress(0, 10); 
         for (int i = 0; i < 10; i++) { 
         Thread.sleep(100); 
         } 
         updateMessage("Finish!"); 
         return new Rectangle((380)/3,(380)/3,colors[counter]); 
        } 
       }; 
      } 
    }; 

    //StateListener 
    RecBuilder.stateProperty().addListener(new ChangeListener<Worker.State>() { 
     @Override public void changed(ObservableValue<? extends Worker.State> observableValue, 
         Worker.State oldState, Worker.State newState) { 
      switch (newState) { 
      case SCHEDULED: 
       break; 
      case READY: 
      case RUNNING: 
       break; 
      case SUCCEEDED: 
       Rectangle rec = RecBuilder.valueProperty().getValue(); 
       indicators[counter].progressProperty().unbind(); 
       loading[counter].textProperty().unbind(); 
       loadPane.getChildren().set(counter, rec); 
       if(counter<8){ 
        counter++; 
        nextPane(RecBuilder); 
       } 
       break; 
      case CANCELLED: 
      case FAILED: 
       loading[counter].textProperty().unbind(); 
       loading[counter].setText("Failed!"); 
       if(counter<8){ 
        counter++; 
        nextPane(RecBuilder); 
       } 
       break; 
      } 
     } 
    }); 

    //begin PanelBuilding: 
    nextPane(RecBuilder); 
} 

private void nextPane(Service<Rectangle> recBuilder) { 
    loading[counter].textProperty().bind(recBuilder.messageProperty()); 
    indicators[counter].visibleProperty().bind(recBuilder.progressProperty().isNotEqualTo(new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS))); 
    recBuilder.restart(); 
} 

private Node createLoadPane() { 
    loadPane = new TilePane(5,5); 
    loadPane.setPrefColumns(3); 
    loadPane.setPadding(new Insets(5)); 
    for(int i=0;i<9;i++){ 
     StackPane waitingPane = new StackPane(); 
     Rectangle background = new Rectangle((380)/3, (380)/3, Color.WHITE); 
     indicators[i] = new ProgressIndicator(); 
     indicators[i].setPrefSize(50, 50); 
     indicators[i].setMaxSize(50, 50); 
     indicators[i].setTranslateY(-25); 
     indicators[i].setTranslateX(-10); 
     loading[i] = new Label(); 
     loading[i].setTranslateY(25); 
     waitingPane.getChildren().addAll(background,indicators[i],loading[i]); 
     loadPane.getChildren().add(waitingPane); 
    } 

    return loadPane; 
} 

public static void main(String[] args) { 
    launch(args); 
} 

} 
+0

謝謝。我認爲問題是一個任務(更好的單個任務實例)不能運行多次。將任務實例放在一個方法中,讓我們通過每個方法調用重新初始化它,這也爲我解決了這個問題。尼斯:) – 2015-04-18 13:01:33