[javafx] JavaFX : 초기화 중에 컨트롤러에서 스테이지를 가져 오는 방법은 무엇입니까?

컨트롤러 클래스에서 스테이지 이벤트 (즉, 숨기기)를 처리하고 싶습니다. 그래서 제가해야 할 일은 리스너를 추가하는 것입니다.

((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);

하지만 문제는 초기화가

Parent root = FXMLLoader.load(getClass().getResource("MyGui.fxml"));

그리고 전에

Scene scene = new Scene(root);
stage.setScene(scene);

따라서 .getScene ()은 null을 반환합니다.

내가 찾은 유일한 해결 방법은 myPane.sceneProperty ()에 리스너를 추가하는 것입니다. 그리고 그것이 null이 아닐 때 씬이 생기면 .windowProperty () my! goddamn! 마침내 단계를 검색하는 리스너 처리. 그리고 그것은 모두 이벤트를 준비하기 위해 원하는 리스너를 설정하는 것으로 끝납니다. 듣는 사람이 너무 많다고 생각합니다. 내 문제를 해결하는 유일한 방법입니까?



답변

FXMLLoader를 통해 초기화 후 컨트롤러의 인스턴스를 가져올 수 getController()있지만 FXMLLoader정적 메서드를 사용하는 대신를 인스턴스화해야합니다 .

load()나중에 컨트롤러에 직접 호출 한 후 스테이지를 전달합니다 .

FXMLLoader loader = new FXMLLoader(getClass().getResource("MyGui.fxml"));
Parent root = (Parent)loader.load();
MyController controller = (MyController)loader.getController();
controller.setStageAndSetupListeners(stage); // or what you want to do


답변

필요한 것은 AnchorPaneID 를 제공하는 것뿐입니다. 그러면 ID를 얻을 수 있습니다 Stage.

@FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();

여기에서 Listener필요한 것을 추가 할 수 있습니다 .

편집 : 아래 EarthMind에서 언급했듯이 AnchorPane요소 일 필요는 없습니다 . 정의한 모든 요소가 될 수 있습니다.


답변

나는 그것이 당신이 원하는 대답이 아니라는 것을 알고 있지만 IMO에서 제안 된 해결책은 좋지 않습니다. 왜? 애플리케이션 상태에 따라 달라지기 때문입니다. JavaFX에서 컨트롤, 장면 및 스테이지는 서로 의존하지 않습니다. 즉, 컨트롤은 장면에 추가하지 않고도 살 수 있으며 장면은 무대에 연결하지 않고도 존재할 수 있습니다. 그런 다음 순간 t1에서 제어가 장면에 연결될 수 있고 순간 t2에서 해당 장면이 무대에 추가 될 수 있습니다.

따라서 컨트롤러 참조를 가져오고 메서드를 호출하고 스테이지를 전달하여 애플리케이션에 상태를 추가하는 방법을 제안합니다. 즉, 스테이지가 생성 된 직후 적절한 순간에 해당 메서드를 호출해야합니다. 즉, 지금 주문을 따라야합니다. 1- 단계 생성 2- 생성 된 단계를 메서드를 통해 컨트롤러에 전달합니다.

이 접근 방식에서는이 순서를 변경할 수 없거나 변경해서는 안됩니다. 그래서 무국적 상태를 잃었습니다. 그리고 소프트웨어에서 일반적으로 상태는 악합니다. 이상적으로 메서드는 호출 순서를 요구하지 않아야합니다.

그렇다면 올바른 솔루션은 무엇입니까? 두 가지 대안이 있습니다.

1- 당신의 접근 방식, 컨트롤러 청취 속성에서 무대를 얻습니다. 이것이 올바른 접근 방식이라고 생각합니다. 이렇게 :

pane.sceneProperty().addListener((observableScene, oldScene, newScene) -> {
    if (oldScene == null && newScene != null) {
        // scene is set for the first time. Now its the time to listen stage changes.
        newScene.windowProperty().addListener((observableWindow, oldWindow, newWindow) -> {
            if (oldWindow == null && newWindow != null) {
                // stage is set. now is the right time to do whatever we need to the stage in the controller.
                ((Stage) newWindow).maximizedProperty().addListener((a, b, c) -> {
                    if (c) {
                        System.out.println("I am maximized!");
                    }
                });
            }
        });
    }
});

2- 당신은 당신이 만드는 곳에서 당신이해야 할 일을합니다 Stage(그리고 그것은 당신이 원하는 것이 아닙니다).

Stage stage = new Stage();
stage.maximizedProperty().addListener((a, b, c) -> {
            if (c) {
                System.out.println("I am maximized!");
            }
        });
stage.setScene(someScene);
...


답변

컨트롤러에서 스테이지 객체를 얻는 가장 간단한 방법은 다음과 같습니다.

  1. (컨트롤러 클래스에서 스테이지를 설정하는 setter 메소드가 될 것입니다)와 같이 자체 생성 된 컨트롤러 클래스에 추가 메소드를 추가합니다.

    private Stage myStage;
    public void setStage(Stage stage) {
         myStage = stage;
    }
    
  2. 시작 방법에서 컨트롤러 가져 오기 및 단계 설정

    FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
    OwnController controller = loader.getController();
    controller.setStage(this.stage);
    
  3. 이제 컨트롤러에서 스테이지에 액세스 할 수 있습니다.


답변

fx : id를 할당 하거나 모든 노드 (anchorpane, button 등)에 변수를 선언합니다. 그런 다음 여기에 이벤트 핸들러를 추가하고 해당 이벤트 핸들러 내에 아래에 주어진 코드를 삽입합니다.

Stage stage = (Stage)((Node)((EventObject) eventVariable).getSource()).getScene().getWindow();

희망, 이것은 당신을 위해 작동합니다 !!


답변

Platform.runLater는 초기화가 완료 될 때까지 실행을 방지합니다. 이 경우 창 너비를 조정할 때마다 목록보기를 새로 고치고 싶습니다.

Platform.runLater(() -> {
    ((Stage) listView.getScene().getWindow()).widthProperty().addListener((obs, oldVal, newVal) -> {
        listView.refresh();
    });
});

당신의 경우

Platform.runLater(()->{
    ((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
});


답변

당신과 함께 얻을 수 있습니다 node.getScene당신은에서 호출하지 않는 경우, Platform.runLater결과는 널 값입니다.

null 값의 예 :

node.getScene();

null 값이없는 예 :

Platform.runLater(() -> {
    node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
               //your event
     });
});