Détecter lorsque la scène est de nouveau mise au point et que la scène est chargée

Nov 22 2020

J'ai une scène parent, au-dessus de laquelle une fenêtre contextuelle peut être affichée. Voici le code:

private static Stage chooseBreedStage;
    static {
        chooseBreedStage = new Stage();
        chooseBreedStage.setTitle("Choose breed");
        chooseBreedStage.initOwner(AppKitty.getStage());
        chooseBreedStage.initModality(Modality.WINDOW_MODAL);
        chooseBreedStage.setScene(SceneManager.getInstance().getScene(SceneEnum.CHOOSE_BREED_SCREEN));
    }

    public void showChooseBreedPopup() {
        chooseBreedStage.showAndWait();
    }

Avant d'afficher la fenêtre contextuelle, je brouille le nœud parent par la méthode setEffect (). Comment puis-je supprimer l'effet de flou lorsque la fenêtre contextuelle est fermée?

Dans mes tentatives, je suis toujours confronté à un problème avec malgré le fait que le popup disparaît déjà, les éléments annotés par @FXML dans le contrôleur d'écran parent sont nuls, mais ils sont déjà visibles et ne sont pas masqués par le popup

Existe-t-il un écouteur qui gère les événements lorsque la scène n'est pas bloquée et que la scène est déjà chargée, afin que je puisse interagir avec les objets @FXML?

Voici une partie du contrôleur de scène qui se trouve dans la phase principale:

        public class MainScreenController {
        private GaussianBlur blur = new GaussianBlur();
            @FXML
            public StackPane mainScreen;
        
            public void blurOn() {
                mainScreen.setEffect(blur);
            }
            public void blurOff() {
                mainScreen.setEffect(null);
            }
        public void makeTestClick(ActionEvent event) {
            blurOn();
           SceneManager.getInstance().getController(ChooseBreedScreenController.class)
                    .showChooseBreedPopup(); 
        }
    }

Code de classe SceneManager (@Data est une annotation lombok, peut être remplacé par des getters ad setters):

public class SceneManager {
    private final Map<SceneEnum, SceneData> sceneData = new HashMap<>();

    @Data
    private class SceneData {
        private Scene scene;
        private FXMLLoader loader;
        private Controller controller;

        SceneData(Scene scene, FXMLLoader loader) {
            setScene(scene);
            setLoader(loader);
            setController(controller);
        }
    }

    private static SceneManager instance = new SceneManager();

    public static SceneManager getInstance() {
        return instance;
    }

    private SceneManager() {
    }

    public <T extends Controller> T getController(Class<T> controllerClass) {
        SceneEnum sceneEnum = getCorrespondingEnum(controllerClass);
        if (sceneData.get(sceneEnum) == null || sceneData.get(sceneEnum).getController() == null) {
            initSceneController(controllerClass);
        }
        return (T) sceneData.get(sceneEnum).getController();
    }

    public Controller getController(SceneEnum sceneEnum) {
        return getController(sceneEnum.getControllerClass());
    }

    private <T extends Controller> void initSceneController(Class<T> controllerClass) {
        try {
            SceneEnum sceneEnum = getCorrespondingEnum(controllerClass);
            if (sceneData.get(sceneEnum) == null) {
                initScene(sceneEnum);
            }
            sceneData.get(sceneEnum).setController(controllerClass.getConstructor().newInstance());
        } catch (Exception e) {
            //todo here should be popup with error
        }
    }

    private <T extends Controller> SceneEnum getCorrespondingEnum(Class<T> controllerClass) {
        Optional<SceneEnum> desiredSceneEnum = Arrays.stream(SceneEnum.values())
                .filter(sceneEnum -> controllerClass.isAssignableFrom(sceneEnum.getControllerClass()))
                .findFirst();
        return desiredSceneEnum.orElseGet(() -> {
            //todo here should be shown popup with error
            return null;
        });
    }

    public Scene getScene(SceneEnum sceneEnum) {
        if (sceneData.get(sceneEnum) == null) {
            initScene(sceneEnum);
        }
        return sceneData.get(sceneEnum).getScene();
    }

    private void initScene(SceneEnum sceneEnum) {
        ConsumerWithException<SceneEnum, IOException> loadingScene = sceneType -> {
            FXMLLoader loader = getFxmlLoader(sceneEnum);
            Scene scene = new Scene(loader.load());
            sceneData.put(sceneEnum, new SceneData(scene, loader));
        };
        try {
            loadingScene.accept(sceneEnum);
        } catch (IOException initializeScreenException) {
            try {
                //Loading app error popup scene, before calling getController() method for
                //this popup, to avoid recursion if loading app error popup scene producing exception as well
                //(it may be in initScene method inside getController method)
                loadingScene.accept(SceneEnum.APP_ERROR_POPUP);
                getController(AppErrorPopupController.class)
                        .showAppErrorPopup(sceneEnum);
            } catch (IOException initializeErrorPopupException) {
                //todo make a better logging
                initializeErrorPopupException.printStackTrace();
            }
        }
    }

    private FXMLLoader getFxmlLoader(SceneEnum scene){
        return new FXMLLoader(this.getClass().getResource(scene.getScenePath()));
    }
}

Classe AppKitty:

public class AppKitty extends Application {
    private static Stage stage;

    public static Stage getStage() {
        return stage;
    }

    public static void setScene(SceneEnum sceneEnum) {
        getStage().setScene(SceneManager.getInstance()
                        .getScene(sceneEnum));
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        stage = primaryStage;
        primaryStage.setTitle("AppKitty");
        primaryStage.setScene(SceneManager.getInstance().getScene(SceneEnum.MAIN_SCREEN));
        primaryStage.show();
    }
}

mainScreen.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.geometry.Insets?>
<StackPane xmlns="http://javafx.com/javafx"
           xmlns:fx="http://javafx.com/fxml"
           fx:controller="applicationinterface.controllers.MainScreenController"
           prefHeight="400.0" prefWidth="600.0"
           fx:id="mainScreen"
           stylesheets="@../styles/mainScreenBackground.css"
           id="background_image">

    <Label fx:id="title" text="What do you want?" alignment="TOP_CENTER"
           stylesheets="@../styles/outline.css" styleClass="outline" StackPane.alignment="TOP_CENTER">

    </Label>
    <HBox
            fx:id="bottomBar" id="outline.label" alignment="BOTTOM_CENTER"
            stylesheets="@../styles/outline.css" spacing="20" StackPane.alignment="BOTTOM_CENTER">
        <StackPane.margin>
            <Insets bottom="10"/>
        </StackPane.margin>
        <Button fx:id="randomKittyButton" text="Random Kitty" onAction="#randomKittyClick" focusTraversable="false"
                stylesheets="@../styles/buttonBorder.css" styleClass="button"/>
        <Button fx:id="makeTestButton" text="Take the test" onAction="#makeTestClick" focusTraversable="false"
                stylesheets="@../styles/buttonBorder.css" styleClass="button"/>
    </HBox>
</StackPane>

Réponses

1 SaiDandem Nov 22 2020 at 23:15

Selon votre code, vous devez inclure les gestionnaires de fermeture pour l'étape popup au moment de la déclaration dans votre bloc statique. Vous pouvez inclure l'un des gestionnaires ci-dessous. (Dépend de vos besoins)

chooseBreedStage.setOnCloseRequest(e1->{
    // Remove blur of AppKitty.getStage()
});

chooseBreedStage.addEventHandler(WindowEvent.WINDOW_HIDDEN,e1->{
    // Remove blur of AppKitty.getStage()
});

chooseBreedStage.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST,e1->{
    // Remove blur of AppKitty.getStage()
});