11

I would like to block the owner window for a popup in JavaFX.

I initialize my popup like this:

popUp = new Popup();
popUp.getContent().add(content);
popUp.show(pane.getScene().getWindow());

With this, I can still work in the first window (pane window). I would like to disable this action and I would like the user just works in the popup.

How to do this ?

Thanks.

Kiva
  • 9,193
  • 17
  • 62
  • 94

4 Answers4

22

Use a Stage instead of a Popup.

Before showing the stage, invoke stage.initModality as either APPLICATION_MODAL or WINDOW_MODAL, as appropriate. Also invoke stage.initOwner to the parent window of your new stage so that it will appropriately block it for the WINDOW_MODAL case.

Stage stage = new Stage();
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(pane.getScene().getWindow());
stage.setScene(new Scene(content));
stage.show();
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 1
    Shouldn't be Modality.APPLICATION_MODAL instead of Modality.WINDOW_MODAL? at least in my case it works with the former as suggested in the other user's answer, but not with the later. – Fran Marzoa Oct 14 '18 at 21:34
  • It depends upon what you want to do Fran. If you want to block all windows in the application, then use `APPLICATION_MODAL`. If you only want to block the parent window chain (as the original question asks), then use `WINDOW_MODAL`. If you are blocking the parent window with `WINDOW_MODAL`, then you MUST call `initOwner` on your window with a valid, non-null, parent window reference, BEFORE you show your window, otherwise it won't block anything. – jewelsea Oct 15 '18 at 00:51
4

Thanks, optimal solution: example with FXML load file:

@Override
    public void start(Stage primaryStage) throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("DialogView.fxml"));
        primaryStage.initModality(Modality.APPLICATION_MODAL); // 1 Add one
        Scene scene = new Scene(root);        
        primaryStage.setScene(scene);
        primaryStage.initOwner(primaryStage.getScene().getWindow());// 2 Add two
        primaryStage.show();

    }

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

    }
  • Not working for me. :( Using Kotlin in IntelliJ Idea over OS X Mojave. Followed those steps, but I still can interact with the original window after opening the new one. – Fran Marzoa Oct 14 '18 at 21:31
  • Oh Damn it! I mixed your answer with the previous one and I used Modality.WINDOW_MODAL with did NOT work. But APPLICATION_MODAL does! Thanks! – Fran Marzoa Oct 14 '18 at 21:33
0

I'm using JavaFX11. Both this and this works with a small change. Here is my working example. I'm using rgielen's javafx-weaver

Main:

package com.featuriz.controller;

import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Text;
import net.rgielen.fxweaver.core.FxControllerAndView;
import net.rgielen.fxweaver.core.FxmlView;
import org.springframework.stereotype.Component;

@Component
@FxmlView("/com/featuriz/ui/Login.fxml")
public class LoginController {
    
    private final FxControllerAndView<InfoDialogController, AnchorPane> infoDialog;

    @FXML
    private Text featuriz;

    public LoginController(FxControllerAndView<InfoDialogController, AnchorPane> infoDialog) {
        this.infoDialog = infoDialog;
    }

    @FXML
    public void initialize() {
        featuriz.setOnMouseClicked(
                actionEvent -> this.infoDialog.getController().show()
        );
    }
}

Dialog:

package com.featuriz.controller;

import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import net.rgielen.fxweaver.core.FxmlView;
import org.springframework.stereotype.Component;

@Component
@FxmlView("/com/featuriz/ui/InfoDialog.fxml")
public class InfoDialogController {

    private Stage stage;

    @FXML
    private Label lbl_info;

    @FXML
    private Button closeButton;

    @FXML
    private AnchorPane dialog_info;

    @FXML
    public void initialize() {
        Scene scene = new Scene(dialog_info);
        scene.setFill(Color.TRANSPARENT);
        this.stage = new Stage();
        this.stage.initModality(Modality.APPLICATION_MODAL);
        this.stage.initStyle(StageStyle.TRANSPARENT);
        this.stage.setScene(scene);
        this.stage.setAlwaysOnTop(true);

        String javaVersion = System.getProperty("java.version");
        String javafxVersion = System.getProperty("javafx.version");
        lbl_info.setText("JavaFX " + javafxVersion + "\nRunning on Java " + javaVersion + ".");

        closeButton.setOnAction(
                actionEvent -> this.stage.close()
        );
    }

    public void show() {
        this.stage.show();
    }

}
Sudhakar Krishnan
  • 732
  • 1
  • 8
  • 27
0

You just have to add the Modality resource from javafx.stage.Modality;

And then add the line stage.initModality(Modality.APPLICATION_MODAL);

Here you have an example

Stage stage = new Stage();

            Parent root = FXMLLoader.load(getClass().getResource( -- pathInterface --));
            root.getStylesheets().add(getClass().getResource( -- pathCss --).toExternalForm());
            stage.initStyle(StageStyle.DECORATED.UNDECORATED);
            stage.initModality(Modality.APPLICATION_MODAL);
HttpDefi
  • 9
  • 3