스테이지가 다시 초점을 맞추고 장면이로드 될 때 감지

Nov 22 2020

팝업을 표시 할 수있는 상위 단계가 있습니다. 다음은 코드입니다.

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

팝업을 표시하기 전에 setEffect () 메서드로 부모 노드를 흐리게 처리합니다. 팝업이 닫힐 때 흐림 효과를 제거하려면 어떻게해야합니까?

내 시도에서 팝업이 이미 사라 졌음에도 불구하고 항상 문제가 발생했습니다. 부모 화면 컨트롤러에서 @FXML 주석이 달린 요소는 null이지만 이미 표시되고 팝업으로 숨겨지지 않습니다.

스테이지가 차단되지 않고 장면이 이미로드되어있을 때 이벤트를 처리하는 리스너가있어 @FXML 객체와 상호 작용할 수 있습니까?

다음은 기본 단계에서 설정된 장면 컨트롤러의 일부입니다.

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

SceneManager 클래스 코드 (@Data는 lombok 주석이며 getter ad setter로 대체 가능) :

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

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>

답변

1 SaiDandem Nov 22 2020 at 23:15

코드에 따라 정적 블록에 선언 할 때 팝업 단계에 대한 닫기 핸들러를 포함해야합니다. 아래 핸들러 중 하나를 포함 할 수 있습니다. (필요에 따라 다름)

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