JavaFx 다이얼로그
주 윈도우에서 알림 또는 사용자의 입력을 위해서 실행되는 서브 윈도우
자체적으로 실행될 수 없고, 주 윈도우(소유자 윈도우)에 의해서 실행
- 모달 다이얼로그
: 다이얼로그를 닫기 전 까지 소유자 윈도우를 사용할 수 없음
- 모달리스 다이얼로그
: 다이얼로그를 닫아도 소유자 윈도우 계속 사용 가능
1. FileChooser, DIrectoryChooser
- FileChooser
: 로컬 PC의 파일을 선택할 수 있는 다이얼로그 - 컨트롤이 아니기 때문에 FXML에서 선언할 수 없음
: showOpenDialog() 또는 showSaveDialog()를 호출해야 함
: 모달 다이얼로그 이므로 [열기] 또는 [저장] 버튼을 클릭하거나, [취소] 버튼을 클릭하기 전까지는 소유자 윈도우를 사용할 수 없음
- DirectoryChooser
: 파일이 아닌 디렉토리(폴더)를 선택하고 싶을 때 사용
2. Popup
투명한 컨테이너를 제공하는 모달리스 다이얼로그
: 윈도우의 기본 장식(아이콘, 제목, 최소화 및 복원 버튼, 닫기 버튼) 없음
: 자바 코드로 작성하거나, FXML 파일로 작성
: 다른 윈도우보다 최상위 위치에 놓임
: 모달리스 다이얼로그 - Popup을 닫기 위해서는 주 윈도우(소유자 윈도우)를 닫거나, Popup 안에 추가된 컨트롤의 이벤트를 처리해서 hide() 메소드를 호출해야 함
: setAutoHide(true)로 설정 시 다른 윈도우로 포커스를 이동하면 Popup은 자동으로 닫힘
팝업 내용을 정의
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<HBox xmlns:fx="http://javafx.com/fxml"
alignment="CENTER_LEFT" style="-fx-background-color: black; -fx-background-radius: 20;" >
<children>
<ImageView id="imgMessage" fitHeight="30" fitWidth="30" preserveRatio="true"/>
<Label id="lblMessage" style="-fx-text-fill: white;">
<HBox.margin>
<Insets left="5.0" right="5.0" />
</HBox.margin>
</Label>
</children>
</HBox>
3. 커스텀 다이얼로그
다양한 내용의 다이얼로그를 만들고 싶다면 Stage로 직접 생성
StageStyle 열거 상수와 윈도우 스타일
확인 다이얼로그 내용을 정의
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<AnchorPane prefHeight="150.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
<children>
<ImageView fitHeight="50" fitWidth="50" layoutX="15" layoutY="15" preserveRatio="true">
<image><Image url="@images/dialog-info.png" /></image>
</ImageView>
<Button id="btnOk" layoutX="336.0" layoutY="104.0" text="확인" />
<Label id="txtTitle" layoutX="87.0" layoutY="33.0" prefHeight="15.0" prefWidth="290.0" />
</children>
</AnchorPane>
4. 컨트롤러에서 primaryStage 사용
: 컨트롤러에서 다이얼로그를 실행할 때, 소유자 윈도우가 될 primaryStage가 필요
- 메인 클래스에서 전달하는 방법
: 메인 클래스의 start() 매개값으로 전달
- 컨테이너 또는 컨트롤러로부터 얻는 방법
: initialize() 메소드 안에서는 사용 불가
실행 클래스
package sec09.exam01_dialog;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class AppMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("root.fxml"));
Parent root = loader.load();
RootController controller = loader.getController();
controller.setPrimaryStage(primaryStage);
Scene scene = new Scene(root);
primaryStage.setTitle("AppMain");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
선언적 레이아웃
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.geometry.*?>
<HBox xmlns:fx="http://javafx.com/fxml" fx:controller="sec09.exam01_dialog.RootController"
alignment="TOP_LEFT" spacing="10.0" >
<children>
<Button text="Open FileChooser" onAction="#handleOpenFileChooser"/>
<Button text="Save FileChooser" onAction="#handleSaveFileChooser"/>
<Button text="DirectoryChooser" onAction="#handleDirectoryChooser"/>
<Button text="Popup" onAction="#handlePopup"/>
<Button text="Custom" onAction="#handleCustom"/>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
컨트롤러
package sec09.exam01_dialog;
import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Modality;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class RootController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
}
private Stage primaryStage;
public void setPrimaryStage(Stage primaryStage) {
this.primaryStage = primaryStage;
}
public void handleOpenFileChooser(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(
new ExtensionFilter("Text Files", "*.txt"),
new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.gif"),
new ExtensionFilter("Audio Files", "*.wav", "*.mp3", "*.aac"),
new ExtensionFilter("All Files", "*.*"));
File selectedFile = fileChooser.showOpenDialog(primaryStage);
if (selectedFile != null) {
System.out.println(selectedFile.getPath());
}
}
public void handleSaveFileChooser(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().add(new ExtensionFilter("All Files", "*.*"));
File selectedFile = fileChooser.showSaveDialog(primaryStage);
if (selectedFile != null) {
System.out.println(selectedFile.getPath());
}
}
public void handleDirectoryChooser(ActionEvent e) {
DirectoryChooser directoryChooser = new DirectoryChooser();
File selectedDir = directoryChooser.showDialog(primaryStage);
if (selectedDir != null) {
System.out.println(selectedDir.getPath());
}
}
public void handlePopup(ActionEvent e) throws Exception {
Popup popup = new Popup();
Parent parent = FXMLLoader.load(getClass().getResource("popup.fxml"));
ImageView imageView = (ImageView) parent.lookup("#imgMessage");
imageView.setImage(new Image(getClass().getResource("images/dialog-info.png").toString()));
imageView.setOnMouseClicked(event->popup.hide());
Label lblMessage = (Label)parent.lookup("#lblMessage");
lblMessage.setText("메시지가 왔습니다.");
popup.getContent().add(parent);
popup.setAutoHide(true);
popup.show(primaryStage);
}
public void handleCustom(ActionEvent e) throws Exception {
Stage dialog = new Stage(StageStyle.UTILITY);
dialog.initModality(Modality.WINDOW_MODAL);
dialog.initOwner(primaryStage);
dialog.setTitle("확인");
Parent parent = FXMLLoader.load(getClass().getResource("custom_dialog.fxml"));
Label txtTitle = (Label) parent.lookup("#txtTitle");
txtTitle.setText("확인하셨습니까?");
Button btnOk = (Button) parent.lookup("#btnOk");
btnOk.setOnAction(event->dialog.close());
Scene scene = new Scene(parent);
dialog.setScene(scene);
dialog.setResizable(false);
dialog.show();
}
}
'Java > 17. JavaFX' 카테고리의 다른 글
Day 29 : JavaFX CSS 스타일 - 외부 CSS 파일 (0) | 2021.11.26 |
---|---|
Day 29 : JavaFX CSS 스타일 - inline 스타일 (0) | 2021.11.26 |
Day 28 : JavaFX 메뉴바와 툴바 (0) | 2021.11.25 |
Day 28 : JavaFX 컨트롤 - 차트 컨트롤 (0) | 2021.11.25 |
Day 28 : JavaFX 컨트롤 - 미디어 컨트롤 (0) | 2021.11.25 |