无法在 JavaFX 中更改警报 window 的 initModality

Can't change initModality of an Alert window in JavaFX

在 JavaFX (11) 中,我试图在主 window 上方显示警报 window,但我不希望主 window 可点击。为此,我想我必须更改该警报的 initModality window(https://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html 参见 'Modality')。它不起作用是因为警报的所有者 window 为空吗?

这是我的控制器 class。 main class 只是 IntelliJ IDEA 生成的默认 JavaFX Main class,而 .fxml 文件只是一个带有用于测试目的的按钮的锚定窗格。

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
    }
}

主 window 中的按钮仍然可以按下,因此 initModality 不起作用。我也用 Modality.WINDOW_MODALModality.NONE 试过了,没有变化。

如果重要的话,我正在 Linux 使用 bspwm。

我通过将警报代码放在 Platform.runLater() 方法中来修复它,如下所示:

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");
        });
    }

主要 window 现在不是交互式的,就像我想要的那样。

我认为问题在于 windows 的显示顺序。使用以下内容进行测试重现了 Windows 10(使用 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();
    }

}

以上结果导致对话框 window 不是正确的模态。但是,如果您在 primaryStage.show() 之后将 alert.show() 移至 primaryStage.show(),则一切正常。

由于您在 FXML 控制器的 initialize() 方法中显示您的 Alert,因此很可能在您显示主要 window 之前执行了代码。如果您想在应用程序开始时显示 Alert,至少有两个选项:

  1. Platform.runLater 调用中调用 show(),就像在 中一样。

    • 这样做的缺点是它使您的代码高度依赖于看似无关的代码。例如,如果出于某种原因您更改了主要 window 的显示方式和时间,则此选项可能会中断。
  2. 向您的 Controller 添加一个方法 class 并在显示您的另一个 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();
    }