JavaFX File Chooser

The newest version of the JavaFX FileChooser uses native FileChoosers to allow the selection of files. This means that the FileChooser is guaranteed to pass Apple Store requirements on having the OS and not the app control file system operations. However, it also means that the look and feel of your app may clash with the look and feel of the JavaFX file chooser, thus providing a degraded user experience. Most would say that is a fair trade off, as customers will already be used to their OS’s file chooser, and custom a JavaFX file chooser might hurt the user experience.

This short JavaFX tutorial goes into the three most common FileChooser uses. They are:

  1. Choosing one file to open
  2. Choosing multiple files to open
  3. Saving to a file

We’ll go into all three uses with examples.

Note: If you are new to programming JavaFX, I suggest glancing over the “What is JavaFX?” article to get a feel for creation of JavaFX projects in Eclipse. Also, there are plenty of other JavaFX tutorials that avoid FXML at my JavaFX without FXML page, if that’s your thing. 😉

To start with, you need to understand two JavaFX classes and one standard Java class. So let’s take a look at them.

First, there is the JavaFX FileChooser class. It is isn’t Java’s first file chooser class. If you’re a long time Java programmer, you’ve probably used the older JFileChooser in Swing. If you’ve used the older file chooser, you’ll like the simplicity of the newer JavaFX javafx.stage.FileChooser.

The FileChooser is a dialog made specifically for browsing the file system, and loading files. When using the JavaFX FileChooser, you’ll need to give it a title, define the file extensions it is allowed to look at, and associate it with the window (stage) that your app is focused on.

The ExtensionFilter is a simple class used for defining file types that JavaFX FileChoosers are interested in. When constructing ExtensionFilters, you give a label and all file extensions associated with that label as arguments to the constructor.

Finally, the Java IO API’s File class. If you’ve ever used Java file IO, then you already have some knowledge of the File class. When the call to FileChooser’s show methods return, you get a File object defining the file in the file system the user chose or a null, meaning they didn’t choose a valid file, maybe because they clicked cancel.

Before getting into the FileChooser code, let’s create a skeleton app to play with. All the app has is a window with a JavaFX TextArea and a JavaFX Button for clicking. This class has a HandleClick() method that we will fill out with JavaFX FileChooser related code so it is easy to change for our three example.

Note: Depending on the user’s OS, the Dialog title may or may not be shown.

Here’s the base code before adding the FileChooser code.

package com.whatisjavafx;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class Main extends Application {
  //need access to this in
  //the on action event handler
  private TextArea ta;
  
  @Override
  public void start(Stage stage) {
    //setting up a container
    VBox root = new VBox();

    //adding a text area node
    ta = new TextArea();
    ta.setPrefSize(400, 200);
    ta.setText("Just some default text ...\n");
    root.getChildren().add(ta);
    
    //we'll want a button and
    //an event handler
    Button pick = new Button("Choose...");
    pick.setOnAction( event -> {
      handleClick();
    });
    root.getChildren().add(pick);
    
    //adding it all to the scene and stage
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
  }
  
  /**
   * Handling the JavaFX ActionEvent
   * caused by the button click.
   * 
   * This is where all the cool
   * FileChooser stuff happens.
   */
  private void handleClick() {
    ta.appendText("click!\n");
  }

  public static void main(String[] args) {
    launch(args);
  }
}

 

All this code does is append “click!” to the text in the TextArea, as shown in the image. You can paste the code into your JavaFX’s main class.

Before the JavaFX FileChooser
This is the app before we add in the JavaFX FileChooser code.

Now let’s add a bit more code. All we’ll focus on from here on out is the handleClick() method. The handleClick() method is called by the action event that is triggered when we click on the JavaFX Button. It has access to our JavaFX Stage and our JavaFX TextArea.

Suppose we want to select one text file, and append the text to our JavaFX TextArea? You would modify the handleClick() method as follows.

  private void handleClick() {
    FileChooser fc = new FileChooser();
    fc.setTitle("Get Text");
    fc.getExtensionFilters().addAll(
        new ExtensionFilter("Text Files", "*.txt"),
        new ExtensionFilter("All Files", "*.*"));
    File phil = fc.showOpenDialog(stage);
    if (phil != null) {
      try {
        String content = 
            new Scanner(phil)
            .useDelimiter("\\Z")
            .next();
        ta.appendText(content);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
    }

 

First we construct a FileChooser. Then we set the title of the JavaFX FileChooser. The title may not be shown on some operating systems.

The tricky bit, is that we create JavaFX ExtensionFilters for the types of files that we want the file chooser to accept. I suggest that you always add a “All Files” ExtensionFilter in case the user is trying to load a file with an extension that you did not anticipate.

Once the desired file extensions have been configured, all showOpenDialog(). If you call it with the JavaFX Stage as a parameter, the file chooser dialog will likely be attached to your Stage’s window. If that will impede the user’s experience in some way–for example, they need information from the window in order to select a the correct file–then pass in null instead of the Stage to get a free floating file choosers dialog.

Note: If you attach the file chooser to a JavaFX Stage, the Stage will block all user interaction until the file chooser returns. Just use “null” for your argument if you don’t want this behavior. The downside is that you get a free floating file chooser dialog.

Finally, the returned value from the show method is passed to a File object. The File will be null, if the user did not select a valid File, or if they cancelled the action. You should always test for null.

For this example, I quickly scan in the entire file and append it to the end of the JavaFX TextArea.

Simple.

Now, let’s change the code to open multiple text files.

  private void handleClick() {
    FileChooser fc = new FileChooser();
    fc.setTitle("Get Text");
    fc.getExtensionFilters().addAll(
        new ExtensionFilter("Text Files", "*.txt"),
        new ExtensionFilter("All Files", "*.*"));
    List<File> phils = fc.showOpenMultipleDialog(stage);
    if (phils != null) {
      try {
        String content;
        for (File phil : phils) {
          content = 
              new Scanner(phil)
              .useDelimiter("\\Z")
              .next();
          ta.appendText(content);
        }
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
    }
  }

 

Not much has changed.

We call showOpenMultipleDialog(), now. You’ll notice that we get a List<File> back from the FileChooser instead of a single File object. However, we still check for a null return and we still handle the File objects the same way.

Now for the save dialog. Here’s the code.

  private void handleClick() {
    FileChooser fc = new FileChooser();
    fc.setTitle("Get Text");
    fc.getExtensionFilters().addAll(
        new ExtensionFilter("Text Files", "*.txt"),
        new ExtensionFilter("All Files", "*.*"));
    File phil = fc.showSaveDialog(stage);
    if (phil != null) {
      try (PrintStream ps = new PrintStream(phil)) {
        ps.print(ta.getText());
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
    }
  }

 

If you understood the open dialogs, you probably won’t find anything too surprising about the save dialog. The user choses (or creates a file), then you spit your data out to the file in a Java IO friendly way you like. Once again, if the user cancels the dialog instead of choosing a file, you will get a null back from the user instead of a valid File Object.

And that’s all there is to using a JavaFX FileChooser.

Leave a Reply

Your email address will not be published. Required fields are marked *