首先,我是 JavaFX 的新手,如果这个问题很愚蠢,我很抱歉。如何从任务中获取返回对象?
这是我的问题:
我想从 Mock 中获取对象列表。Mock 有 1 到 5 秒的延迟。但我不希望我的 GUI 在这个时候冻结。
在 Java.Swing 中,使用 Thread 很容易,但据我所知,JavaFX 有 Tasks。
我已经阅读了很多教程,但是它们到处都返回一个文本属性。所以这是我的问题:如何使用任务/线程(在我的情况下为列表)的计算结果设置对象的值
谢谢你。
首先,我是 JavaFX 的新手,如果这个问题很愚蠢,我很抱歉。如何从任务中获取返回对象?
这是我的问题:
我想从 Mock 中获取对象列表。Mock 有 1 到 5 秒的延迟。但我不希望我的 GUI 在这个时候冻结。
在 Java.Swing 中,使用 Thread 很容易,但据我所知,JavaFX 有 Tasks。
我已经阅读了很多教程,但是它们到处都返回一个文本属性。所以这是我的问题:如何使用任务/线程(在我的情况下为列表)的计算结果设置对象的值
谢谢你。
射线,
你是对的,这些例子似乎掩盖了从任务中获取结果。有两种方法可以取回我知道的结果:
getValue()
Task类的方法(我是这样做的)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
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 中的并发性。这更深入地解释了并发,服务,任务......
希望能帮助到你!