首页 > 解决方案 > Javafx Stage.show() 稍后打开

问题描述

当我运行此代码时,阶段会在任务完成后显示。为什么会这样?如何使阶段出现在任务之前?

private List<SensorEntity> detectSensors() throws URISyntaxException {


    Task<List<SensorEntity>> task = new TryDetectTask(sensorForDiscover, wifiController);

    ProgressIndicator indicator = new ProgressIndicator();

    indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
    indicator.progressProperty().bind(task.progressProperty());

    Stage stage = new Stage();
    stage.setHeight(100);
    stage.setWidth(200);
    stage.initModality(WINDOW_MODAL);
    stage.setScene(new Scene(indicator));

    stage.show();


    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<List<SensorEntity>> futureTask = executor.submit(task, null);

    try {
        return  futureTask.get(30, SECONDS);
    } 
    catch (InterruptedException | ExecutionException | TimeoutException e) {
        log.error(e);
        e.printStackTrace();
    }
    executor.shutdown();
    return null;
}

pane.getScene().setRoot()、alert.show()、Platform.runLater 等的结果相同,但 showAndWait() 工作正常。

标签: multithreadingjavafx

解决方案


futureTask.get(30, SECONDS)阻塞,直到结果可用或 30 秒过去。由于您在 JavaFX 应用程序线程上执行此操作,因此在此期间阻止对 GUI 的任何更新。

showAndWait“有效”,因为此调用确保 GUI 仍然更新,但此方法仅在阶段关闭时返回,这意味着您稍后只需冻结 GUI。

您最好将 a 传递Consumer<List<SensorEntity>>给使用任务结果执行代码的方法。

private void detectSensors(Consumer<List<SensorEntity>> consumer) throws URISyntaxException {
    final boolean[] boolRef = new boolean[1];

    Task<List<SensorEntity>> task = new TryDetectTask(sensorForDiscover, wifiController);
    task.setOnSucceeded(evt -> {
        if (!boolRef[0]) {
            boolRef[0] = true;
            // submit result unless timeout happened
            consumer.accept(task.getValue());
        }
    });

    ProgressIndicator indicator = new ProgressIndicator();

    indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
    indicator.progressProperty().bind(task.progressProperty());

    Stage stage = new Stage();
    stage.setHeight(100);
    stage.setWidth(200);
    stage.initModality(WINDOW_MODAL);
    stage.setScene(new Scene(indicator));

    stage.show();

    // a thread does not need to be shut down
    Thread thread = new Thread(task);
    thread.setDaemon(true);

    PauseTransition pause = new PauseTransition(Duration.seconds(30));
    pause.setOnFinished(evt -> {
        if (!boolRef[0]) {
            boolRef[0] = true;
            // submit null unless task has finished successfully
            consumer.accept(null);
        }
    });

    thread.start();
    pause.play();
}

推荐阅读