Difference between revisions of "컴퓨터프로그래밍및실습 (2022년)/1128"
Jump to navigation
Jump to search
Line 461: | Line 461: | ||
=== JavaFX Scene Builder === | === JavaFX Scene Builder === | ||
[[file:CP-SceneBuilder-1.png | thumb | Scene Builder로 root.fxml 띄움]] | |||
* Scene Builder 다운로드 - https://gluonhq.com/products/scene-builder/ | * Scene Builder 다운로드 - https://gluonhq.com/products/scene-builder/ | ||
* [https://marketplace.visualstudio.com/items?itemName=bilalekrem.scenebuilderextension SceneBuilder extension for Visual Studio Code] | * [https://marketplace.visualstudio.com/items?itemName=bilalekrem.scenebuilderextension SceneBuilder extension for Visual Studio Code] | ||
Line 466: | Line 467: | ||
*** 경로를 다음과 같이 지정한다 : C:\Users\profs\AppData\Local\SceneBuilder 폴더의 SceneBuilder.exe 지정 | *** 경로를 다음과 같이 지정한다 : C:\Users\profs\AppData\Local\SceneBuilder 폴더의 SceneBuilder.exe 지정 | ||
* Scene Builder 띄우는 방법 | * Scene Builder 띄우는 방법 | ||
** fxml 파일을 선택한다. | ** fxml 파일을 선택한다. |
Revision as of 15:24, 21 July 2022
JavaFX 개요
- AWT
- Native UI 컴포넌트 사용
- 운영체제 마다 UI 모양이 다름
- Swing
- 운영체제가 제공하는 native UI 사용 안 함
- 운영체제가 새롭게 제공하는 UI 지원의 어려움
- JavaFX
- Abode의 flash, Microsoft의 silverlight의 대항마
- JDK 7부터 지원. JDK 8 권장.
- JDK 11부터는 별도로 설치해야 함.
- 화면 레이아웃과 스타일, 애플리케이션 로직 분리
- Java 코드와 분리해서 스타일 시트(CSS)로 외관 작성 → 개발자와 디자이너의 동시 개발 가능
- Java 코드에서도 레이아웃과 애플리케이션 로직을 분리하고 싶다면 레이아웃은 FXML로 작성, 로직은 Java로 작성
- JavaFX 애플리케이션 구성 요소
[레이아웃] 자바 코드 파일 또는 FXML 파일 |
[외관 및 스타일] CSS 파일 |
[리소스] 그림 파일 동영상 파일 ... |
[비즈니스 로직] 자바 코드 파일 |
JavaFX 애플리케이션 개발 시작
메인 클래스
import javafx.application.Application;
import javafx.stage.Stage;
public class AppMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX 라이프사이클(life cycle)
- 예제 코드
import javafx.application.Application;
import javafx.stage.Stage;
public class AppMain extends Application {
public AppMain() {
System.out.println(Thread.currentThread().getName() + ": AppMain() 호출");
}
@Override
public void init() throws Exception {
System.out.println(Thread.currentThread().getName() + ": init() 호출");
}
@Override
public void start(Stage primaryStage) throws Exception {
System.out.println(Thread.currentThread().getName() + ": start() 호출");
primaryStage.show();
}
@Override
public void stop() throws Exception {
System.out.println(Thread.currentThread().getName() + ": stop() 호출");
}
public static void main(String[] args) throws Exception {
System.out.println(Thread.currentThread().getName() + ": main() 호출");
launch(args);
}
}
- 실행 결과
main: main() 호출
JavaFX Application Thread: AppMain() 호출
JavaFX-Launcher: init() 호출
JavaFX Application Thread: start() 호출
JavaFX Application Thread: stop() 호출 ← 프로그램을 끝내야 실행된다.
메일 클래스 실행 매개값 얻기
C:> java AppMain --ip=192.168.0.5 --port=50001
- main()에서 launch(args)를 넘겨 받음
- init() 메소드에서 아래와 같이 실행할 수 있음
Parameters params = getParameters();
List<String> list = params.getRaw();
Map<String, String> map = params.getNamed();
무대(Stage)와 장면(Scene)
- 윈도우 : Stage
- Stage에는 하나의 Scene을 가질 수 있음
- Scene은 직접 생성해야 함
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class AppMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
root.setPrefWidth(350);
root.setPrefHeight(150);
root.setAlignment(Pos.CENTER);
root.setSpacing(20);
Label label = new Label();
label.setText("Hello, JavaFX");
label.setFont(new Font(50));
Button button = new Button();
button.setText("확인");
button.setOnAction(event->Platform.exit());
root.getChildren().add(label);
root.getChildren().add(button);
Scene scene = new Scene(root); // VBox를 루트 컨테이너(root container)로 해서 Scene 생성
primaryStage.setTitle("AppMain입니다");
primaryStage.setScene(scene); // 윈도우에 장면 설정
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX 레이아웃
프로그램적 레이아웃
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class AppMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
HBox hbox = new HBox();
hbox.setPadding(new Insets(10));
hbox.setSpacing(10);
TextField textField = new TextField();
textField.setPrefWidth(200);
Button button = new Button();
button.setText("확인");
ObservableList list = hbox.getChildren();
list.add(textField);
list.add(button);
Scene scene = new Scene(hbox);
primaryStage.setTitle("AppMain");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML 레이아웃
- FXML 파일 (root.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<HBox xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets top="10" right="10" bottom="10" left="10"/>
</padding>
<spacing>10</spacing>
<children>
<TextField>
<prefWidth>200</prefWidth>
</TextField>
<Button>
<text>확인</text>
</Button>
</children>
</HBox>
- AppMain 클래스
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 {
Parent root = FXMLLoader.load(getClass().getResource("root.fxml")); // ← FXML 로드
Scene scene = new Scene(root);
primaryStage.setTitle("AppMain");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
레이아웃(layout) 여백: 패딩(padding)과 마진(margin)
- Margin, Padding 설정 방법
// top, right, bottom, left를 모두 동일한 값으로 설정할 때
// Insets(double topRightBottomLeft)
new Insets(50);
// top, right, bottom, left를 다를 값으로 설정할 때
// Insets(double top, double right, double bottom, double left)
new Insets(10, 20, 30, 40);
- 패딩과 마진 적용 예
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class AppMain extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// 패딩 설정
HBox hbox = new HBox();
hbox.setPadding(new Insets(50, 10, 10, 50));
Button button = new Button();
button.setPrefSize(100, 100);
// 마진 설정
// HBox hbox = new HBox();
// Button button = new Button();
// button.setPrefSize(100, 100);
// HBox.setMargin(button, new Insets(10, 10, 50, 50));
hbox.getChildren().add(button);
Scene scene = new Scene(hbox);
primaryStage.setTitle("AppMain");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML 작성 규칙
프로그램적 레이아웃 자바 코드 | FXML 레이아웃 태그 |
---|---|
HBox hbox = new HBox(); hbox.setPadding(new Inset(10, 10, 10, 10)); hbox.setSpacing(10); |
<HBox xmlns:fx="http://javafx.com/fxml"> <padding> <Insets top="10" right="10" bottom="10" left="10"/> </padding> </HBox> |
TextField textField = new TextField(); textField.setPrefWidth(200); |
<TextField> <prefWidth>200</prefWidth> </TextField> |
Button button = new Button(); button.setText("확인"); |
<Button> <text>확인</text> </Button> |
ObsetvableList list = hbox.getChildren(); list.add(textField); list.add(button); |
<children> <TextField> <prefWidth>200</prefWidth> </TextField> <Button> <text>확인</text> </Button> </children> |
패키지(package) 선언
자바 코드 | FXML 태그 |
---|---|
import javafx.scene.layout.HBox; | <?import javafx.scene.layout.HBox?> |
import javafx.scene.control.*; | <?import javafx.scene.control.*?> |
- <?import?>가 들어가는 위치는 <?xml ...>와 루트 컨테이너 태그 사이이다.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.*?>
<루트 컨테이너 xmlns:fx="http://javafx.com/fxml">
...
</루트 컨테이너>
- import를 제대로 하지 않으면 not a valid type 메시지와 함께 javafx.fxml.LoadException 발생
태그(tag) 선언
- 시작 태그와 끝 태그가 매칭되어야 한다.
자바 코드 | FXML |
---|---|
Button button = new Button(); button.setText("확인"); |
<Button> <text>확인</text> </Button> |
속성(attribute) 선언
- 속성은 "나 '로 감싸야 한다.
<태그이름 속성명="값" 속성명='값'> ... </태그이름>
- 속성명은 Setter 메소드 명이 옴
- 모든 Setter가 사용될 수 있는 것은 아님. 기본 타입(boolean, byte, short, char, int, long, float, double)의 값을 세팅하거나, String을 세팅하는 Setter만 올 수 있음
- 예
자바 코드 | FXML (Setter 태그) | FXML (Setter 속성) |
---|---|---|
Button button = new Button(); button.setText("확인"); |
<Button> <text>확인</text> </Button> |
<Button text="확인"/> |
객체 선언
클래스 속성
- 생성자에 매개 변수가 있고, 매개 변수에 @NamedArg(javafx.beans.NamedArg) 어노테이션이 적용되어 있으면 속성명이나 자식 태그로 작성할 수 있음
<클래스 매개변수="값"> |
<클래스> <매개변수>값</매개변수> </클래스> |
- 예
- HBox를 패딩할 때 setPadding(Insets value) 메소드를 사용하는데
- Insets는 기본 생성자가 없고,
- Insets(double topRightBottomLeft) 또는 Insets(double top, double right, double bottom, double left)만 있음
- 이 경우 아래와 같이 선언 가능함
프로그램적 레이아웃 자바 코드 | FXML 레이아웃 태그 |
---|---|
HBox hbox = new HBox(); hbox.setPadding(new Inset(10, 10, 10, 10)); hbox.setSpacing(10); |
<HBox> <padding> <Insets top="10" right="10" bottom="10" left="10"/> </padding> </HBox> |
클래스 fx:value
- 클래스가 valueOf(String) 메소드를 제공하는 경우
<클래스 fx:value="값" />
기본 코드 | FXML |
---|---|
String.valueOf("Hello, World!"); Integer.valueOf("1"); Double.valueOf("1.0"); Boolean.valueOf("false"); |
<String fx:value="Hello, World!"/> <Integer fx:value="1"/> <Double fx:value="1.0"/> <Boolean fx:value="false"/> |
클래스 fx:constant
- 클래스에 정의된 상수값을 얻고 싶을 경우
<클래스 fx:constant="상수" />
기본 코드 | FXML |
---|---|
Button button = new Button(); button.setMaxWidth( Double.MAX_VALUE ); |
<Button> <maxWidth> <Double fx:constant="MAX_VALUE"/> </maxWidth> <Button> |
클래스 fx:factory
- 어떤 클래스는 new 연산자로 객체를 생성할 수 없고,
- 정적 메소드(이를 factory 메소드라 부른다)로 객체를 얻어야 하는 경우가 있음
<클래스 fx:factory="정적메소드" />
- 예:
ObservableList
의 구현 객체는javafx.collections.FXCollections
의 정적 메소드인observableArrayList(E... items)
메소드로 얻을 수 있다.
기본 코드 | FXML |
---|---|
ComboBox combo = new ComboBox(); combo.setItems(FXCollections.observableArrayList("공개", "비공개")); |
<ComboBox> <Items> <FXCollections fx:factory="observableArrayList"> <String fx:value="공개"/> <String fx:value="비공개"/> </FXCollections> </items> </ComboBox> |
FXML 로딩과 Scene 생성
- FXML 파일을 작성한 후 이를 이용하여 객체를 만들어야 한다. 이를 FXML loading이라고 한다.
- javafx.fxml.FXMLLoader를 이용
- 두 개의 load() 메소드 : 정적 메소드, 인스턴스 메소드
Parent root = FXMLLoader.load(getClass().getResource("xxx.fxml"));
- getClass() - 현재 클래스 리턴
- getResource() - 클래스가 위치하는 곳에서 상대 경로로 리소스의 URL을 리턴
- load() - FXML 파일을 로딩
FXMLLoader loader = new FXMLLoader(getClass().getResource("xxx.fxml"));
Parent root = (Parent)loader.load();
- load() - Parent 타입을 리턴함. 이것은 FXML 파일에서의 루트 태그로 선언된 컨테이너임
- 만을 루트 태그가 <HBox> 라면 다음과 같이 작성해도 됨
HBox hbox = (HBox) FXMLLoader.load(getClass().getResource("xxx.fxml"));
- 예제 코드
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 {
Parent root = FXMLLoader.load(getClass().getResource("root.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("AppMain");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX Scene Builder
- Scene Builder 다운로드 - https://gluonhq.com/products/scene-builder/
- SceneBuilder extension for Visual Studio Code
- vscode에서 Ctrl-Shift-P를 눌러 "Configure Scene Builder path"를 실행한다.
- 경로를 다음과 같이 지정한다 : C:\Users\profs\AppData\Local\SceneBuilder 폴더의 SceneBuilder.exe 지정
- vscode에서 Ctrl-Shift-P를 눌러 "Configure Scene Builder path"를 실행한다.
- Scene Builder 띄우는 방법
- fxml 파일을 선택한다.
- vscode에서 Ctrl-Shift-P를 누른다.