40

My problem is that all the examples of using FileChooser requires you to pass in a stage. Only problem is that my UI is defined in an fxml file, which uses a controller class separate from the main stage.

@FXML protected void locateFile(ActionEvent event) {
    FileChooser chooser = new FileChooser();
    chooser.setTitle("Open File");
    chooser.showOpenDialog(???);
}

What do I put at the ??? to make it work? Like I said, I don't have any references to any stages in the controller class, so what do I do?

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131

4 Answers4

70

For any node in your scene (for example, the root node; but any node you have injected with @FXML will do), do

chooser.showOpenDialog(node.getScene().getWindow());
James_D
  • 201,275
  • 16
  • 291
  • 322
  • and where do I get the root node from? do I have to define an `fx:id` or am I completely missing the idea? – Electric Coffee Aug 25 '14 at 18:13
  • 7
    Yes, define an `fx:id`. But you don't have to use the root node, just use anything for which you already have an `fx:id` and have injected into the controller (all your nodes are in the same scene...). You could also do `Node node = (Node) event.getSource();` but I like that less, because of the downcast. – James_D Aug 25 '14 at 18:29
  • 1
    Could you please elaborate on this answer a bit? For starters, what's a "node" in this context, and how do I "define a fx:id", and where? I copied over the line from above, but the "node" part still cannot be resolved. – Sargon1 Nov 26 '15 at 08:15
  • To comment on @Sargon1 request: A node is any widget in the UI which inherits from Node. A "fx:id" is the name of the Java UI Object in your class. You connect the associated fxml component over the [Scenebuilder App](http://gluonhq.com/labs/scene-builder/) (also possible directly in the fxml code, of course): when you open an fxml file and chose the desired widget, you simply set the id (name of object) under the right accordion-menu "Code" and the appearing field "fx:id". – David Artmann Aug 26 '16 at 10:26
19

You don't have to stick with the Stage created in the Application you can either:

@FXML protected void locateFile(ActionEvent event) {
    FileChooser chooser = new FileChooser();
    chooser.setTitle("Open File");
    File file = chooser.showOpenDialog(new Stage());
}

Or if you want to keep using the same stage then you have to pass the stage to the controller before:

    FXMLLoader loader = new FXMLLoader(getClass().getResource("yourFXMLDocument.fxml"));
    Parent root = (Parent)loader.load();
    MyController myController = loader.getController();
    myController.setStage(stage);

and you will have the main stage of the Application there to be used as you please.

Mansueli
  • 6,223
  • 8
  • 33
  • 57
  • 7
    I think it is better to set the owner of the dialog to the correct stage and not some made up stage. See [showOpenDialog javadoc](http://docs.oracle.com/javase/8/javafx/api/javafx/stage/FileChooser.html#showOpenDialog-javafx.stage.Window-) "If the owner window for the file dialog is set, input to all windows in the dialog's owner chain is blocked while the file dialog is being shown.". If you don't specify the correct stage, the modal dialog blocking functionality of the FileChooser is not enabled. It is usually desirable to have modal blocking in a FileChooser. – jewelsea Aug 25 '14 at 22:16
  • 3
    @jewelsea It is a *better* practice o keep using the same Stage, and that's why I show in my answer one way to do it. But it should be noted that best practice isn't the *only practice*. – Mansueli Aug 25 '14 at 22:21
2

Alternatively, what worked for me: simply put null.

@FXML
private void onClick(ActionEvent event) {
    File file = fileChooser.showOpenDialog(null);
    if (file != null) {
       //TODO
    }
}
luke8800gts
  • 398
  • 3
  • 7
  • curious....won't `null` create a non-modal dialog box? which in most cases, a File Open dialog is typically Modal – GoldBishop Oct 06 '21 at 14:01
1

From a menu item

public class SerialDecoderController implements Initializable {

  @FXML
  private MenuItem fileOpen;

  @Override
  public void initialize(URL url, ResourceBundle rb) {
    // TODO
 }    


public void fileOpen (ActionEvent event) {

    FileChooser fileChooser = new FileChooser();
    fileChooser.setTitle("Open Resource File"); 
    fileChooser.showOpenDialog(fileOpen.getParentPopup().getScene().getWindow());

}