2013-11-03 72 views
1

首先,我是JavaFX的新手,很抱歉,如果這個問題很愚蠢。我如何從任務中獲取返回對象?如何從任務內設置Var?

我的繼承人問題:

我想從一個模擬對象的名單。模擬從1到5秒延遲。但我不想,我的GUI在這個時候凍結。

在Java.Swing中,使用Thread很容易,但據我所知,JavaFX具有Tasks。

我讀過很多教程,但無處不在,他們返回一個文本屬性。所以這裏是我的問題:我如何設置一個對象的值與任務/線程(在我的情況下是一個列表)的計算結果

謝謝。

回答

2

雷,

你是正確的,該例子似乎掩蓋從任務找回結果。有兩種方法,你可以得到返回結果,我知道:

  1. 通過Task類的getValue()方法(這是我做的方式)
  2. 通過父FutureTask的get()方法類(我沒有使用過,但原則上它應該可以工作)。

隨着第一getValue()形式給出,你需要確保任務將通過在任務的調用方法updateValue(...)方法的價值。然後把聽者的WorkerStateEvent

myTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() { 

    @SuppressWarnings("unchecked") 
    @Override 
    public void handle(WorkerStateEvent event) { 
     ReturnType rt = (ReturnType) event.getSource().getValue() 
     // ... other stuff to do here ... 
    } 
}); 

第一種方法是有點冗長,但它的工作原理,並允許一些更復雜的操作任務完成後。

第二種方法稍微簡單明瞭,但不會給予您在任務完成時控制該做什麼的太多控制。使用FutureTask的get()方法,代碼應該阻塞,直到任務返回值爲止。

// 
// Start the task in a thread (using whatever approach you like) 
//before calling the get() method. 
// 
ReturnType rt = myTask.get(); 

我已經使用Future對象與其他代碼,但我沒用過FutureTask與FX API,所以我不能告訴你,如果有隱藏的陷阱在裏面:所以用它作爲應儘可能簡單。

祝你好運,

chooks

+0

感謝您的回答,我發現我的錯誤。如果任務完成,我忘了添加一個EventHandler。所以我把allways稱爲task.getValue(),但Task仍然是runnig,所以值爲空。 – ray

2

的任務是一個通用型。這意味着如果您將類型應用於像Task<Integer>這樣的任務,Task類將具有返回Integer的函數。其中一個功能是valueProperty(),可以綁定到其他場景元素。顯示在一個標籤,或任何其他。我建議你閱讀the javafx binding tutorial,以獲得更好的理解。

以下是任務使用或其屬性的示例。

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.concurrent.Task; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.ListView; 
import javafx.scene.control.ProgressBar; 
import javafx.scene.layout.HBox; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

public class TestingTasks extends Application{ 

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

    @Override 
    public void start(Stage stage) throws Exception { 

     VBox vbox = new VBox(10); 
     vbox.setAlignment(Pos.TOP_CENTER); 

     ListView<String> list = new ListView<>(); 
     HBox hbox = new HBox(10); 
     hbox.setAlignment(Pos.CENTER_LEFT); 
     Label labelMessage = new Label(); 
     hbox.getChildren().addAll(new Label("Message: "), labelMessage); 
     ProgressBar progress = new ProgressBar(-1); 
     progress.setVisible(false); 

     Button button = new Button("Executing Task"); 
     button.setOnAction(event(button, list, progress, labelMessage)); 

     vbox.getChildren().addAll(list, hbox, button, progress); 
     Scene scene = new Scene(vbox, 400, 300); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    private EventHandler<ActionEvent> event(final Button button, final ListView<String> list, final ProgressBar progress, final Label labelMessage) {  
     return new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       Task<ObservableList<String>> task = generateTask(); 
       list.itemsProperty().bind(task.valueProperty()); 
       progress.visibleProperty().bind(task.runningProperty()); 
       labelMessage.textProperty().bind(task.messageProperty()); 
       button.disableProperty().bind(task.runningProperty()); 
       task.runningProperty().addListener(listenerRunningTask()); 
       Thread t = new Thread(task); 
       t.setDaemon(true); 
       t.start(); 
      } 

     }; 
    } 

    private Task<ObservableList<String>> generateTask() {    
     return new Task<ObservableList<String>>() {     
      @Override 
      protected ObservableList<String> call() throws Exception { 
       updateMessage("Waiting..."); 
       Thread.sleep(5000); 
       updateMessage("Waking up"); 
       return FXCollections.observableArrayList("One", "Two", "Three"); 
      } 
     }; 
    } 

    private ChangeListener<? super Boolean> listenerRunningTask() {  
     return new ChangeListener<Boolean>() { 
      @Override 
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 
       if(oldValue && !newValue){ 
        //TODO when finish 
       }    
      } 
     }; 
    } 
} 

因此,基本上,你可以在任務返回一個變量,或者等待任務結束,並執行一些東西,建立自己的綁定...

如果你想修改從屏幕上的東西線程,你需要從FX線程完成,任務函數調用在FX線程之外,因此屏幕不會凍結。但所有綁定元素都將出現在FX線程中,因此可以安全地修改GUI。

如果你想從一個不FX線程安全地修改GUI,只是做:

Platform.runLater(new Runnable() {     
    @Override 
    public void run() { 
     //Safe modification in the FX Thread 
    } 
}); 

也採取concurrency in JavaFX2看看。這更深入地解釋了併發性,服務,任務...

希望它有幫助!