Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't change initModality of an Alert window in JavaFX

In JavaFX (11), I'm trying to show an alert window above the main window, but I don't want the main window to be clickable. To do this, I thought I had to change the initModality of that alert window (https://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html see 'Modality'). Does it not work because the owner of the alert window is null?

Here's my controller class. The main class is just the default JavaFX Main class generated by IntelliJ IDEA and the .fxml file is just an anchorpane with a button for testing purposes.

package sample;

import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.stage.Modality;

public class Controller {

    public Button button;

    public void initialize(){
        Alert alert = new Alert(Alert.AlertType.ERROR);
        System.out.println(alert.getOwner());             //output: null
        alert.initModality(Modality.APPLICATION_MODAL);
        alert.setHeight(200);
        alert.setWidth(300);
        alert.show();
        button.setOnAction(push -> System.out.println("button pressed")); //button is still pressable
    }
}

The button in the main window is still pressable, so the initModality didn't work. I also tried it with Modality.WINDOW_MODAL and Modality.NONE, no change.

I'm on Linux with bspwm if that matters.

like image 277
zjeffer Avatar asked Oct 21 '25 09:10

zjeffer


2 Answers

I believe the issue is the order the windows are shown. Testing this with the following reproduced the issue on Windows 10 (using JavaFX 12.0.1):

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        var alert = new Alert(AlertType.INFORMATION);
        alert.initModality(Modality.APPLICATION_MODAL);
        alert.setHeaderText(null);
        alert.setContentText("This is a test of application modality.");
        alert.show();

        primaryStage.setScene(new Scene(new StackPane(new Label("Hello, World!")), 500, 300));
        primaryStage.show();
    }

}

The above results in a dialog window that isn't properly modal. However, if you move alert.show() to after primaryStage.show() everything works as expected.

Since you are showing your Alert inside the initialize() method of an FXML controller, it's likely that code is being executed before you show your primary window. If you want to display the Alert right at the start of your application there are at least two options:

  1. Call show() inside a Platform.runLater call, as you do in your answer.

    • The downside to this is that it makes your code highly dependent on seemingly unrelated code. For instance, if for whatever reason you change how and when your primary window is displayed then this option can break.
  2. Add a method to your Controller class and invoke it after showing your other window.

    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader loader = new FXMLLoader(/*location*/);
        primaryStage.setScene(new Scene(loader.load()));
        primaryStage.show();
        loader.<Controller>getController().showMyAwesomeAlert();
    }
    
like image 182
Slaw Avatar answered Oct 22 '25 23:10

Slaw


I fixed it by putting the alert code in a Platform.runLater() method like so:

public void initialize(){
        Alert alert = new Alert(Alert.AlertType.ERROR);    
        alert.initModality(Modality.APPLICATION_MODAL);
        alert.setHeight(200);
        alert.setWidth(300);

        Platform.runLater(alert::show());

        button.setOnAction(push -> {
            System.out.println("button pressed");
        });
    }

The main window is now not interactive, just like I wanted.

like image 31
zjeffer Avatar answered Oct 22 '25 23:10

zjeffer