43

I can't figure out how to create a modal window in JavaFX. Basically I have file chooser and I want to ask the user a question when they select a file. I need this information in order to parse the file, so the execution needs to wait for the answer.

I've seen this question but I've not been able to find out how to implement this behavior.

fabian
  • 80,457
  • 12
  • 86
  • 114
lucaconlaq
  • 1,511
  • 4
  • 19
  • 36

3 Answers3

72

In my opinion this is not good solution, because parent window is all time active.
For example if You want open window as modal after click button...

private void clickShow(ActionEvent event) {
    Stage stage = new Stage();
    Parent root = FXMLLoader.load(
        YourClassController.class.getResource("YourClass.fxml"));
    stage.setScene(new Scene(root));
    stage.setTitle("My modal window");
    stage.initModality(Modality.WINDOW_MODAL);
    stage.initOwner(
        ((Node)event.getSource()).getScene().getWindow() );
    stage.show();
}

Now Your new window is REALY modal - parent is block. also You can use

Modality.APPLICATION_MODAL
Krzysztof Szewczyk
  • 1,752
  • 1
  • 21
  • 25
  • 3
    I had to use stage.initModality(Modality.APPLICATION_MODAL); to block calling parent. Even using showAndWait() did not block the caller (I was calling from a JFXPanel-not sure if that made any difference.) – torwalker Nov 25 '15 at 16:35
52

Here is link to a solution I created earlier for modal dialogs in JavaFX 2.1 The solution creates a modal stage on top of the current stage and takes action on the dialog results via event handlers for the dialog controls.

JavaFX 8+

The prior linked solution uses a dated event handler approach to take action after a dialog was dismissed. That approach was valid for pre-JavaFX 2.2 implementations. For JavaFX 8+ there is no need for event handers, instead, use the new Stage showAndWait() method. For example:

Stage dialog = new Stage();

// populate dialog with controls.
...

dialog.initOwner(parentStage);
dialog.initModality(Modality.APPLICATION_MODAL); 
dialog.showAndWait();

// process result of dialog operation. 
... 

Note that, in order for things to work as expected, it is important to initialize the owner of the Stage and to initialize the modality of the Stage to either WINDOW_MODAL or APPLICATION_MODAL.

There are some high quality standard UI dialogs in JavaFX 8 and ControlsFX, if they fit your requirements, I advise using those rather than developing your own. Those in-built JavaFX Dialog and Alert classes also have initOwner and initModality and showAndWait methods, so that you can set the modality for them as you wish (note that, by default, the in-built dialogs are application modal).

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 3
    ControlsFX library has been developed for JavaFX version 8.0 and above, to be released in Q1 2014, so one must take it into consideration. – bazeusz Dec 05 '13 at 16:26
  • @jewelsea is there any filechooser function for javafx 1.3? – Avinash Raj Aug 25 '15 at 09:48
  • 1
    Avinash, it is best to ask a new question as a new question. JavaFX 1.3 is obsolete, I don't advise using it. I do not think that it directly had a FileChooser, though you might be able to use a Swing [JFileChooser](https://docs.oracle.com/javase/8/docs/api/javax/swing/JFileChooser.html) with it. – jewelsea Aug 25 '15 at 12:35
-1

You can create application like my sample. This is only single file JavaFX application.

public class JavaFXApplication1 extends Application {
    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Stage stage; 
                stage = new Stage();

                final SwingNode swingNode = new SwingNode();

                createSwingContent(swingNode);

                StackPane pane = new StackPane();
                pane.getChildren().add(swingNode);

                stage.initModality(Modality.APPLICATION_MODAL);
                stage.setTitle("Swing in JavaFX");
                stage.setScene(new Scene(pane, 250, 150));
                stage.show();
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void createSwingContent(final SwingNode swingNode) {
        SwingUtilities.invokeLater(() -> {
            try {
                Path currentRelativePath = Paths.get("");
                String s = currentRelativePath.toAbsolutePath().toString();
                JasperDesign jasperDesign = JRXmlLoader.load(s + "/src/reports/report1.jrxml");

                String query = "SELECT * FROM `accounttype`";
                JRDesignQuery jrquery = new JRDesignQuery();
                jrquery.setText(query);
                jasperDesign.setQuery(jrquery);

                JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
                JasperPrint JasperPrint = JasperFillManager.fillReport(jasperReport, null, c);
                //JRViewer viewer = new JRViewer(JasperPrint);

                swingNode.setContent(new JRViewer(JasperPrint));
            } catch (JRException ex) {
                Logger.getLogger(AccountTypeController.class.getName()).log(Level.SEVERE, null, ex);
            }
        });
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
  • 3
    It might improve the quality of your answer if you added an explanation of what about your answer you think will help and why. – toonice Apr 06 '17 at 04:20