在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_MODAL和Modality.NONE进行了尝试,没有任何变化.
如果这很重要,我在Linux上使用bspwm.
解决方法:
我相信问题在于窗口的显示顺序.使用以下命令进行测试,重现了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的,因此在显示主窗口之前,代码可能正在执行.如果要在应用程序开始时立即显示警报,则至少有两个选项:
>在Platform.runLater调用中调用show(),就像在your answer中一样.
>这样做的缺点是它使您的代码高度依赖看似无关的代码.例如,如果出于任何原因更改了显示主窗口的方式和时间,则此选项可能会中断.
>将方法添加到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();
}