본문 바로가기

JavaFX

[JavaFX] JavaFX 모든 윈도우 창 닫기

JavaFX에서 메인화면을 만들고 메뉴의 화면들을 메인화면에 탭형식으로 보여주도록 개발을 했다.

이 때 메인화면을 종료하면 탭으로 분리되어 있던 다른 화면들도 같이 종료가 되야하기 때문에 메인화면을 종료하면

모든 화면들도 종료되도록 하려고 한다.

 

 

 

 

우선 로그인화면 생성 시 윈도우창에 닫기, 확대, 축소가 없는 UI를 만든다.

fxml로 만든 login.fxml을 로드한다. login.fxml을 별다른건 없고 기본 로그인 UI의 형식으로 만들었다.

여기서 중요한건 primaryStage.initStyle() 메소드이다.

initStyle에 들어가는 값은 5가지가 있다.

 

DECORATED : 일반적인 윈도우 화면의 흰색배경 스타일로 타이틀, 축소, 확대, 닫기 버튼을 출력한다.(기본 default 값)

TRANSPARENT : Stage 배경이 투명하고 장식이 없는 스타일로 타이틀, 축소, 확대, 닫기 버튼이 없고 화면이동이 안된다.

UNDECORATED : Stage 배경이 흰색이고 타이틀, 축소, 확대, 닫기버튼이 없는 화면으로 화면이동이 안된다.

UNIFIED : Stage플랫폼 장식으로 스타일을 정의하고 클라이언트 영역과 장식 사이의 경계를 제거

UTILITY : 타이틀 부분에 종료버튼만 보여준다.

 

public void start(Stage primaryStage) {
  try{
    Parent root = FXMLLoader.load(getClass().getResource("login/view/login.fxml"));
    primaryStage.initStyle(StageStyle.UNDECORATED);
    Scene scene = new Scene(root);
    
    primaryStage.setScene(scene);
    primaryStage.show();
  }catch(Exception e){
    e.printStackTrace();
  }
}

 

 

Stage의 StageStyle을 UNDECORATED로 설정하면 화면을 드래그가 불가능해진다.

그럼 너무 불편하기 때문에 UNDECORATED 상태에서도 드래그는 가능하도록 소스를 추가한다.

 

@FXML
private AnchorPane pane;

private Stage stage = null;
private double x = 0;
private double y = 0;

private void stageMove() {
  pane.setOnMousePressed(event) -> {
    x = event.getSceneX();
    y = event.getSceneY();
  });
  
  pane.setOnMouseDragged((event) -> {
    stage = (Stage) pane.getScene().getWindow();
    stage.setX(event.getScreenX() - x);
    stage.setY(event.getScreenY() - y);
  });
  
  pane.setOnMouseReleased((event) -> {
    stage = (Stage) pane.getScene().getWindow();
  });
}

 

 

 

 

메인화면 윈도우창의 닫기 버튼으로 종료 시 이벤트를 설정하여 다른 모든 탭들도 같이 종료될 수 있도록 하려고 한다.

stage에 setOnCloseRequest 이벤트를 추가하여 stage가 종료될 때 이벤트를 발생할 수 있도록 했다.

화면이 종료될 때 Alert창을 띄워 바로 종료되지 않고 사용자가 선택할 수 있도록 했다.

Alert에 입력 값으로는 CONFIRMATION, ERROR, INFORMATION, NONE, WARNING 5가지를 선택할 수 있다.

메소드로는 setTitle , setHeaderText, setContentText 메소드를 사용하여 문구를 수정했다.

버튼 문구는 기본 OK, 취소 문구로 출력된다. 그래서 이 부분도 커스터마이징이 필요하다.

ok, cancel이라든지 확인, 취소라든지 통일도 안된 상태로 출력된다는게 좀 이상하긴 하다.

여튼, ButtonType으로 버튼을 생성 후 alert에 setAll로 버튼을 추가해 준다.

ButtonType이 OK이면 Platform.exit() 로 모든 창을 닫게 한다.

ButtonType이 CANCEL이거나 둘다 아닐 경우 event.consume() 으로 무료화 시킨다.

 

stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
  @Override
  public void handle(WindowEvent event) {
    
    ButtonType btnOk = new ButtonType("확인", ButtonBar.ButtonData.OK_DONE);
    ButtonType btnCancel = new ButtonType("취소", ButtonBar.ButtonData.CANCEL_CLOSE);
    
    Alert alert = new Alert(AlertType.CONFIRMATION, btnOk, btnCancel);
    alert.setTitle("프로그램 종료");
    
    Optional<ButtonType> result = alert.showAndWait();
    if(result.orElse(btnOk) == btnOk) {
      Platform.exit();
    } else {
      event.consume();
    }
  }
}

 

 

또 다른 방법으로 다음과 같이 사용할수도 있다.

 

stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
  @Override
  public void handle(WindowEvent event) {
    
    Button ok = (Button) alert.getDialogPane().lookupButton(ButtonType.OK);
    Button cancel = (Button) alert.getDialogPane().lookupButton(ButtonType.CANCEL);
    
    ok.setText("확인");
    cancel.setText("취소");
    
    Optional<ButtonType> result = alert.showAndWait();
    if(result.get() == ButtonType.OK) {
      Platform.exit();
    } else if(result.get() == ButtonType.CANCEL) {
      event.consume();
    } else {
      event.consume();
    }
  }
}

 

setHeaderText, setGraphic 에 null값을 넣어서 안보이게할 수 있다.

alert.setHeaderText(null);   alert.setGraphic(null);