【问题标题】:JavaFX wait FileChooser showSaveDialog to get selected file pathJavaFX 等待 FileChooser showSaveDialog 以获取选定的文件路径
【发布时间】:2018-07-23 08:11:19
【问题描述】:

我想从 JavaFX 中的 FileChooser showSaveDialog() 对话框中获取选定的文件路径,以便将 tableview 导出到文件。 代码在 Runnable 中运行,因此我必须在 JavaFX 主线程 (Platform.runLater) 中运行 showSaveDialog

public class ExportUtils {
  ...
  private File file = null;
  private String outputPath = null;

  public void Export(){
   ...
   ChooseDirectory(stage);
   if (outputPath != null{
      ...   //export to the selected path
   }
  }

  public void ChooseDirectory(Stage stage) {
      ...
      FileChooser newFileChooser = new FileChooser();
      ...

      Platform.runLater(new Runnable() {
        public void run() {
            file = newFileChooser.showSaveDialog(stage);
            if (file != null) {
                outputPath = file.getPath();
            }
        }
    });
}

我想知道这种情况的最佳解决方案,在我评估 Export() 方法中的 outputPath 变量的值之前,我必须等待用户选择路径和文件名。

【问题讨论】:

    标签: multithreading javafx filechooser


    【解决方案1】:

    除非您需要保持线程运行,否则我建议通过启动新线程而不是在 ExecutorService 上发布任务来处理文件选择。

    如果您确实需要这样做,您可以使用CompletableFuture 来检索结果:

    private static void open(Stage stage, CompletableFuture<File> future) {
        Platform.runLater(() -> {
            FileChooser fileChooser = new FileChooser();
            future.complete(fileChooser.showSaveDialog(stage)); // fill future with result
        });
    }
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        Button button = new Button("start");
    
        button.setOnAction(evt -> {
            new Thread(() -> {
                for (int i = 0; i < 5; i++) {
                    CompletableFuture<File> future = new CompletableFuture<>();
                    open(primaryStage, future);
                    try {
                        File file = future.get(); // wait for future to be assigned a result and retrieve it
                        System.out.println(file == null ? "no file chosen" : file.toString());
                    } catch (InterruptedException | ExecutionException ex) {
                        ex.printStackTrace();
                    }
                }
            }).start();
        });
    
        primaryStage.setScene(new Scene(new StackPane(button)));
        primaryStage.show();
    
    }
    

    注意:如果您在单独的线程中从 ui 访问数据,如果同时修改数据,您可能会遇到麻烦。

    【讨论】:

    • 感谢您的回答。我已经测试过了,效果很好!这就是我要找的。​​span>
    【解决方案2】:

    不要像这样拆分方法。拥有Platform.runLater() 后,您的export() 将无法继续关闭。

    选项 1

    将所有内容组合到一个方法中。

    public void export() {
        ...
    
        Platform.runLater(new Runnable() {
            public void run() {
                file = new FileChooser().showSaveDialog(stage);
                if (file != null) {
                    outputPath = file.getPath();
    
                    // Export to the path
                }
            }
        });
    }
    

    选项 2

    您可以将Platform.runLater() 移动到export() 的开头。

    public void export() {
        ...
        Platform.runLater(() -> {
            String outputPath = chooseDirectory(stage);
            if (outputPath != null) {
                // Export to the path
            }
        });
    }
    
    private String chooseDirectory(Stage stage) {
        ...
        file = new FileChooser().showSaveDialog(stage);
        if (file != null) {
            return file.getPath();
        }
        else return null;
    }
    

    【讨论】:

    • 感谢您的回答。有没有办法等待platform.runlater?比如 CompletableFuture 还是 Future?
    • @user6127833 有,但这样做会更乏味。除非确实需要这样做,否则我不想这样做。选项包括返回未来,在并发 API 中使用高级并发类。
    • 我明白了,也许对于低处理任务来说,这对编码来说太重了,但我知道最终将是程序员的选择,使用并发或简单地将所有导出过程包装在平台稍后运行...谢谢
    猜你喜欢
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    • 2012-09-20
    相关资源
    最近更新 更多