首先,我是JavaFX的新手,很抱歉,如果这个问题很愚蠢。如何从任务中获取返回对象?
继承我的问题:
我想从模拟中获取一个对象列表。模拟的延迟时间为1到5秒。但我不想要,我的GUI在这个时候冻结了。
在Java.Swing中,使用Thread很容易,但就我所知,JavaFX具有Tasks。
我已经阅读了很多教程,但是在任何地方都会返回文本属性。所以这是我的问题:如何使用任务/线程(在我的情况下为列表)中计算结果来设置Object的值
谢谢。
答案 0 :(得分:2)
雷
你是对的,因为这些例子似乎掩盖了从任务中获取结果。您可以通过两种方式获取我所知道的结果:
getValue()
方法(这是我完成它的方式)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()
方法,代码应该阻塞,直到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
答案 1 :(得分: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
}
}
};
}
}
基本上,你可以在Task中返回一个变量,或者等待Task结束并执行一些东西,创建你自己的绑定......
如果你想从线程中修改屏幕的某些内容,你需要从FX线程中执行它,任务函数调用在FX线程之外,因此屏幕不会冻结。但是所有绑定元素都将出现在FX线程中,因此可以安全地修改GUI。
如果要从非FX线程安全地修改GUI,只需执行:
Platform.runLater(new Runnable() {
@Override
public void run() {
//Safe modification in the FX Thread
}
});
另请查看concurrency in JavaFX2。这更深入地解释了并发性,服务,任务......
希望它有所帮助!