10

I'm converting a pure JavaFx app, in which the code below worked fine when put all in one class, to a FXML one, where the Stage declaration and the button handler are in separate classes. In the a Controller, I'm trying to implement a method that will allow the user to choose a directory and store it in a variable for later use:

private File sourceFile;
DirectoryChooser sourceDirectoryChooser;

@FXML
private void handleSourceBrowse() {
        sourceDirectoryChooser.setTitle("Choose the source folder");
        sourceFile = sourceDirectoryChooser.showDialog(theStage);
}

However, "theStage", a Stage which the method requires, only exists(if that's the right terminology) in FolderSyncer4.java:

public class FolderSyncer4 extends Application {

    final String FOLDER_SYNCER = "FolderSyncer";

    Stage theStage;

    @Override
    public void start(Stage primaryStage) throws Exception {
        theStage = primaryStage;

        //TODO do the FXML stuff, hope this works
        Parent root = FXMLLoader.load(getClass().getResource("FolderSyncerMainWindow.fxml"));
        theStage.setScene(new Scene(root, 685, 550));
        theStage.setTitle(FOLDER_SYNCER);
        theStage.show();
    }
}

How to I get around this? I need to have that method implemented again somehow, but suddenly I can't pass the stage as an argument.

Sargon1
  • 854
  • 5
  • 17
  • 48
  • You are referring to `handleSourceBrowse()` in your `.fxml` with an `onAction` attribute on your `Button` element, like `... onAction="#handleSourceBrowse" ...`, right? – Andreas Fester Nov 26 '15 at 07:05
  • Yep, it's there. It prompted me to add @FXML annotation to the handleSourceBrowse() method, so I did(will update the question accordingly), but the problem persists. – Sargon1 Nov 26 '15 at 07:11
  • 1
    Possible duplicate of [How do I open the JavaFX FileChooser from a controller class?](http://stackoverflow.com/questions/25491732/how-do-i-open-the-javafx-filechooser-from-a-controller-class) – Andreas Fester Nov 26 '15 at 08:57

2 Answers2

24

In your situation, it is probably easiest to get the scene from the ActionEvent parameter of your handler:

@FXML
private void handleSourceBrowse(ActionEvent ae) {
    Node source = (Node) ae.getSource();
    Window theStage = source.getScene().getWindow();

    sourceDirectoryChooser.showDialog(theStage);
}

See JavaFX: How to get stage from controller during initialization? for some more information. I am not in favor of the highest rated answer though, since it adds a compile time dependency to the controller after the .fxml file has been loaded (after all that question was tagged with javafx-2, so not sure if the above approach already worked there, and also the context of the question looks a bit different).

See also How do I open the JavaFX FileChooser from a controller class?

Community
  • 1
  • 1
Andreas Fester
  • 36,091
  • 7
  • 95
  • 123
  • I thank you for your answer, but this implementation gives a java.lang.reflect.InvocationTargetException when the button is pressed. – Sargon1 Nov 26 '15 at 09:03
  • Thats strange - I tested it with a simple example, see https://github.com/afester/CodeSamples/tree/master/Java/JavaFXSample/src/com/example/javafx/fxml. Can you paste the stack trace from the exception to pastebin.com or something similar and add the link to it as a comment? – Andreas Fester Nov 26 '15 at 09:11
  • Here it is. Thanks for the help, I'm not too good at deciphering those things. http://pastebin.com/3AycwLge – Sargon1 Nov 26 '15 at 09:16
  • Ok, so the root cause is a `NullPointerException` in line 75 of your controller class - what is the contents of that line? – Andreas Fester Nov 26 '15 at 09:19
  • So, according to your code in the question, did you probably forget to create the `DirectoryChooser`, like `DirectoryChooser sourceDirectoryChooser = new DirectoryChooser();`? That would also explain the NPE. – Andreas Fester Nov 26 '15 at 09:23
  • 1
    Yup, just figured it out too. It seem s to be working now, thanks. – Sargon1 Nov 26 '15 at 09:25
7

Another way is define a static getter for the Stage and Access it

Main Class

public class Main extends Application {
    private static Stage primaryStage; // **Declare static Stage**

    private void setPrimaryStage(Stage stage) {
        Main.primaryStage = stage;
    }

    static public Stage getPrimaryStage() {
        return Main.primaryStage;
    }

    @Override
    public void start(Stage primaryStage) throws Exception{
        setPrimaryStage(primaryStage); // **Set the Stage**
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }
}

Now you Can access this stage by calling

Main.getPrimaryStage()

In Controller Class

public class Controller {
public void onMouseClickAction(ActionEvent e) {
    Stage s = Main.getPrimaryStage();
    s.close();
}
}
Jinu P C
  • 3,146
  • 1
  • 20
  • 29