Не удается изменить initModality окна Alert в JavaFX - PullRequest
3 голосов
/ 19 мая 2019

В JavaFX (11) я пытаюсь показать окно предупреждения над главным окном, но я не хочу, чтобы главное окно было активным. Чтобы сделать это, я подумал, что мне нужно изменить initModality этого окна предупреждения (https://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html, см. «Модальность»). Разве это не работает, потому что владелец окна предупреждения является нулевым?

Вот мой класс контроллера. Основной класс - это просто основной класс JavaFX по умолчанию, сгенерированный IntelliJ IDEA, а файл .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, без изменений.

Я использую bspwm для Linux, если это имеет значение.

Ответы [ 2 ]

2 голосов
/ 19 мая 2019

Я считаю, что проблема заключается в порядке показа окон.Проверка этого с помощью следующего позволила воспроизвести проблему в 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(), все будет работать, как ожидалось.

Поскольку вы показываете Alert в методе initialize() контроллера FXML, этоскорее всего, этот код выполняется до того, как вы покажете свое главное окно.Если вы хотите отобразить Alert в самом начале вашего приложения, есть как минимум две опции:

  1. Вызов show() внутри вызова Platform.runLater, как вы это делаете в ваш ответ .

    • Недостатком этого является то, что он делает ваш код сильно зависимым от, казалось бы, не связанного кода.Например, если по какой-либо причине вы измените способ и время отображения вашего основного окна, эта опция может выйти из строя.
  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();
    }
    
1 голос
/ 19 мая 2019

Я исправил это, поместив код оповещения в метод 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");
        });
    }

Главное окно теперь не интерактивное, как я и хотел.

...