【问题标题】:Can't change initModality of an Alert window in JavaFX无法更改 JavaFX 中警报窗口的 initModality
【发布时间】:2019-10-06 04:11:47
【问题描述】:

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

这是我的控制器类。主类只是 IntelliJ IDEA 生成的默认 JavaFX Main 类,而 .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
    }
}

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

如果这很重要,我在 Linux 上使用 bspwm。

【问题讨论】:

  • 我认为这是因为您的 Alert 最终显示在您的另一个窗口之前。
  • 是不是因为我在initialize()方法中运行了代码?如何确保在我的应用程序启动后立即打开警报窗口?

标签: java javafx java-11


【解决方案1】:

我通过将警报代码放入 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");
        });
    }

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

【讨论】:

    【解决方案2】:

    我认为问题在于窗口的显示顺序。在 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();
        }
    
    }
    

    以上结果导致对话框窗口不正确。但是,如果您将 alert.show() 移动到 primaryStage.show() 之后,一切都会按预期进行。

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

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

      • 这样做的缺点是它使您的代码高度依赖看似不相关的代码。例如,如果您出于某种原因更改了主窗口的显示方式和时间,则此选项可能会中断。
    2. 向您的Controller 类添加一个方法,并在显示您的另一个窗口后调用它。

      @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();
      }
      

    【讨论】:

    • 谢谢,我会使用第二个选项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2017-02-19
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多