1

首先,我是 JavaFX 的新手,如果这个问题很愚蠢,我很抱歉。如何从任务中获取返回对象?

这是我的问题:

我想从 Mock 中获取对象列表。Mock 有 1 到 5 秒的延迟。但我不希望我的 GUI 在这个时候冻结。

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

我已经阅读了很多教程,但是它们到处都返回一个文本属性。所以这是我的问题:如何使用任务/线程(在我的情况下为列表)的计算结果设置对象的值

谢谢你。

4

2 回答 2

2

射线,

你是对的,这些例子似乎掩盖了从任务中获取结果。有两种方法可以取回我知道的结果:

  1. 通过getValue()Task类的方法(我是这样做的)
  2. 通过get()父 FutureTask 类的方法(这个我没用过,但原则上应该可以的)。

使用第一种方法,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 ...
    }
});

第一种方法有点冗长,但它可以在任务完成后进行一些更复杂的操作。

第二种方法更简单直接,但不能让您对任务完成时的操作进行太多控制。使用get()FutureTask 的方法,代码应该阻塞,直到 Task 返回值。所以使用它应该很简单:

//
// 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

于 2013-11-04T13:16:59.433 回答
2

Task 是一个泛型类型。这意味着如果您将类型应用于任务,例如Task<Integer>任务类将具有返回整数的函数。其中一个功能是valueProperty(), 可以绑定到其他场景元素。显示在标签或其他内容中。我建议您阅读javafx 绑定教程,以获得更好的理解。

这是一个使用任务或其属性的示例。

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 线程进行,Task 函数调用位于 FX 线程之外,因此屏幕不会冻结。但是所有的绑定元素都将发生在 FX 线程中,因此可以安全地修改 GUI。

如果您想从非 FX 线程安全地修改 GUI,只需执行以下操作:

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

还要看看JavaFX2 中的并发性。这更深入地解释了并发,服务,任务......

希望能帮助到你!

于 2013-11-04T14:56:03.980 回答