我试图在JavaFX中显示两个同时的阶段,其中第一阶段应该显示一个progessbar,并且一旦第二阶段准备好显示就应该关闭。 我尝试通过 Platform.runLater 和任务运行,但问题是这两个阶段都被冻结,直到两个完成加载并且progessbar开始动画直到第二个舞台完成加载。
这里有一些代码摘录:
public void start(Stage primaryStage) throws Exception {
new Thread(progressTask()).start();
new Thread(loginTask()).start();
}
public Task<Void> loginTask() {
Task<Void> t = new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
Stage s = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("Login.fxml"));
Scene sc = null;
try {
sc = new Scene((Parent) loader.load());
} catch (IOException e) {
e.printStackTrace();
}
s.setScene(sc);
s.show();
}
});
return null;
};
};
return t;
}
public Task<Void> progressTask() {
Task<Void> t = new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
ProgressBar bar = new ProgressBar(0);
bar.setPrefSize(200, 24);
Timeline task = new Timeline(new KeyFrame(Duration.ZERO, new KeyValue(bar.progressProperty(), 0)), new KeyFrame(
Duration.seconds(5), new KeyValue(bar.progressProperty(), 1)));
VBox layout = new VBox(10);
layout.getChildren().setAll(bar);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(new Scene(layout));
stage.initModality(Modality.WINDOW_MODAL);
stage.show();
new Thread() {
public void run() {
task.playFromStart();
}
}.start();
task.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
stage.close();
}
});
}
});
return null;
}
};
感谢您的帮助。
答案 0 :(得分:3)
您应该创建Task
只是为了执行长时间运行的操作,并使用回调来更新UI。很少有人需要自己致电Platform.runLater(...)
。
在您的代码中,Task
完全不起作用,因为它们只是安排所有代码在Platform.runLater(...)
的FX应用程序线程上运行。因此,有效地创建一个新线程只是为了让一些代码在当前线程上执行。
这是一个我认为你想要做的事情的例子:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class DataLoadingStageExample extends Application {
@Override
public void start(Stage primaryStage) {
Scene scene = buildInitialUI();
primaryStage.setScene(scene);
Stage monitorStage = new Stage();
Task<DataClass> dataLoadingTask = createDataLoadingTask();
// update UI when dataLoadingTask finishes
// this will run on the FX Application Thread
dataLoadingTask.setOnSucceeded(event -> {
DataClass data = dataLoadingTask.getValue();
scene.setRoot(createUIFromData(data));
monitorStage.hide();
});
buildProgressUI(monitorStage, dataLoadingTask);
// manage stage layout:
primaryStage.yProperty().addListener((obs, oldY, newY) -> monitorStage.setY(newY.doubleValue() - 100));
primaryStage.setTitle("Application");
// show both stages:
monitorStage.show();
primaryStage.show();
// start data loading in a background thread:
new Thread(dataLoadingTask).start();
}
private void buildProgressUI(Stage monitorStage,
Task<?> task) {
ProgressBar progressBar = new ProgressBar();
progressBar.progressProperty().bind(task.progressProperty());
Scene monitorScene = new Scene(new StackPane(progressBar), 400, 75);
monitorStage.setScene(monitorScene);
monitorStage.setTitle("Loading progress");
}
private Scene buildInitialUI() {
Label loadingLabel = new Label("Loading...");
StackPane root = new StackPane(loadingLabel);
Scene scene = new Scene(root, 600, 400);
return scene;
}
private Task<DataClass> createDataLoadingTask() {
return new Task<DataClass>() {
@Override
public DataClass call() throws Exception {
// mimic connecting to database
for (int i=0; i < 100; i++) {
updateProgress(i+1, 100);
Thread.sleep(50);
}
return new DataClass("Data");
}
};
}
private Parent createUIFromData(DataClass data) {
// obviously much more complex in real life
Label label = new Label(data.getData());
return new StackPane(label);
}
public static class DataClass {
// obviously much more complex in real life
private final String data ;
public DataClass(String data) {
this.data = data ;
}
public String getData() {
return data ;
}
}
public static void main(String[] args) {
launch(args);
}
}