이 포스팅은 JavaFX 실습을 통해 자바 GUI 프로그래밍을 이해하는 것이 목적이다.
JavaFX 는 자바의 GUI 프레임워크이다. 자바가 크로스플랫폼이므로 JavaFX도 크로스플랫폼 GUI 개발이 가능하다.
JavaFX는 자바의 기본 패키지에 포함되지 않으므로 별도로 설치해야 한다. JavaFX 설치는 아래 링크를 참고한다.
GUI 는 그래픽 유저 인터페이스의 약자이다. 우리가 흔히 사용하는 윈도우즈나 스마트폰도 모두 GUI 라고 볼 수 있다. GUI란 단어는 좀 데스크탑이라는 이미지가 남아있어서 최근에는 광범위한 UI, UX 라는 용어를 더 많이 사용한다.
이전 포스팅에서 용어사이에 조금 차이가 나는 부분을 나름의 언어로 설명해봤다. 대부분 우리 일상 생활에서 쓰고 있는 것들이라 개념이 크게 어렵지는 않다.
JavaFX 는 현재는 공식 패키지에 들어있지 않지만 자바 11 버전 이전에는 공식 패키지였다. AWT, SWING 잇는 차세대 GUI 프레임워크로 알려져 있다. AWT 나 SWING 보다 진일보한 GUI 다.
GUI 가 가지는 가장 기본적인 컴포넌트를 보면 다른 어느 GUI 도 비슷하다.
레이블, 버튼, 텍스트필드, 패스워드필드 등의 컴포넌트가 있고,
레이아웃 관리자들이 있다.
또한 키보드 입력과 마우스 클릭 등에 이벤트 발생 시 처리하는 이벤트 핸들러를 인터페이스로 구현한다.
어느 GUI 도구를 사용해도 이 정도는 기본으로 탑재되어 있을 것이다.
JavaFX 는 기존의 기능들 뿐 아니라 CSS 스타일을 적용하는 방법, 터치가 가능한 장치에 사용가능한 인터페이스, 애니메이션, 3D 그리기 등이 가능하다. 아무래도 SWING 이후로 나온 GUI 다 보니 가장 최근의 경향을 반영하고 있다.
GUI 프로그래밍에서 최근 사람들이 비교를 하는 것은 QT in C++, PyQT in Python, JavaFX 이 세개를 주로 하는 것 같다. JavaFX 도 여러가지 기능적인 면에서 충분하다. GUI 자체를 따지는게 아니라 프로그램의 목적이 GUI 를 선택하는 기준이 되야 할 것이다.
아무튼 두서 없이 글을 적고 있는데 JavaFX는 내용이 상당히 많다. 앞서 AWT나 Swing 에 비교해도 다뤄야 할 내용이 한참 많다. 첫 시리즈에서는 전체 흐름을 위해 빠른 진행을 하고 차후 시간이 되면 JavaFX에 대한 내용들을 좀 더 모아서 더 깊이있는 문서를 만들 생각이다.
그러면 바로 코드를 통해 알아보자.
package com;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class Main extends Application implements EventHandler<ActionEvent> {
Button button1;
Button button2;
Label label1;
@Override
public void start(Stage primaryStage) throws Exception{
HBox hbox = new HBox();
hbox.setPadding(new Insets(10));
hbox.setSpacing(10);
label1 = new Label("Label 1");
label1.setFont(new Font("Arial", 30));
primaryStage.setTitle("Button");
button1 = new Button("Button 1");
button1.setOnAction(this);
button1.setPrefSize(100, 30);
button2 = new Button("Button 2");
button2.setOnAction(this);
button2.setPrefSize(100, 30);
hbox.getChildren().add(label1);
hbox.getChildren().add(button1);
hbox.getChildren().add(button2);
primaryStage.setScene(new Scene(hbox, 500, 300));
primaryStage.show();
}
@Override
public void handle(ActionEvent actionEvent) {
if(actionEvent.getSource() == button1){
System.out.println("CLICKED Button 1");
}
if(actionEvent.getSource() == button2){
System.out.println("CLICKED Button 2");
}
}
public static void main(String[] args) {
launch(args);
}
}
GUI 의 가장 기본인 레이블과 버튼, 그리고 버튼의 기능을 구현했다.
* Import 문들
import 문들은 여러가지 쓰는게 많다. javafx 라이브러리를 설치하지 않으면 사용이 불가능하다. 설치는 이 포스트의 맨 앞에 링크가 있다. (인텔리제이 기준)
보면 예전에 Swing 을 쓸때는 javax 였는데 지금은 javafx 이다. IDE를 쓰다보면 자동완성으로 javax 의 클래스들과 이름이 같아서 혼동할 때가 있다. 라이브러리 오류가 날때는 import 문은 javafx 로 시작하는지 확인해준다. Button 이라는 이름이 같아도 어떤 것은 java.awt 의 것도 있다. javafx 패키지에 들은 것을 사용해야 한다.
* public static void main
원래 여기가 프로그램의 시작점인 것은 모두 알고 있을 것이다.
javafx 에서는 launch(args)라는 미리 정의된 메서드만 넣고 실질적인 프로그래밍은 public void start 에 코드를 적는다.
Override 표시가 되어 있다.
* HBox 는 수평 박스 (horizontal)를 의미한다.
컴포넌트를 왼쪽에서 오른쪽으로 추가한다.
메서드가 다양하게 있는데 필요하고 자주 사용되는 것들 위주로 사용하게 된다. 레이아웃 매니저 하나에 수백개나 되는 메서드를 다 외워서 사용하는 사람은 없을 것이다.
* 이제 레이블과 버튼을 만들어보자.
객체로 생성해서 사용할 수 있다. 이전 swing 에서의 Button 컴포넌트와 비교해서 사용방법에 큰 차이가 있지는 않다. 버튼을 생성한 후 레이아웃 매니저에 추가한다. 레이아웃 매니저는 다시 루트 윈도우에 추가한다.
JavaFX 에서는 윈도우를 Stage (무대)라고 한다. 무대에 씬(장면)을 붙이고 다시 씬에 레이아웃 매니저를 붙인다. 언뜻 복잡하게 보일 수 있지만 다양한 기능이 작동하는 GUI를 객체지향 개념으로 최소화 한 것이다.
약간 생소할 수 있겠지만 JFrame 과 별반 차이를 둘 필요는 없을 것 같다. API를 익힐 때 너무 설계적인 부분부터 고민하기 시작하면 진전이 안된다. GUI 같이 복잡한 프로그래밍은 일단은 여러가지 시도를 해보면서 자신에게 맞는 개발 방식을 만드는게 중요하다.
* 액션 이벤트 핸들러를 구현한다. EventHandler는 한개의 메서드를 오버라이드 하면 된다. 인텔리제이에서 Alt + Insert 에 implement 메뉴를 선택하면 메서드가 생성된다. getSource 라는 것은 이벤트가 발생한 객체이다. 즉 버튼이 여러개 있으면 if 문으로 구분이 가능하다. 다른 버튼을 눌렀을 때 다른 기능을 구현할 수 있다. 이것은 인터페이스를 구현한 것이다.
* 이벤트 핸들링은 다른 방법으로도 가능한데 익명함수이다. 이것은 말 그대로 이름이 없다. 이름이 없으니까 한번만 할당해서 사용할 수 있다. 인터페이스의 추상화 메서드를 구현하지 않아도 된다.
익명함수는 class 에 implements 를 삭제하고 사용해야 한다. 인텔리제이에는 자동완성기능이 잘되어 있어서 쉽게 추가할 수 있다.
button1.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
System.out.println("CLICKED Button 1");
}
});
* 더 간단한 코드는 램다식이다. 람다는 표현이 간소화된 함수이다. 모든 것을 함수로 만들다보면 영양가는 없는데 코드만 길어지는 경우가 있다. 이럴때 람다식을 써주면 코드도 줄어들고 관리가 좋아진다.
문법은 차후 단원에서 배우겠으나 람다는 아래와 같은 표기 방식을 사용한다는 것만 이해하자.
button2.setOnAction(e -> System.out.println("CLICKED Button 2"));
* 람다식도 한 줄이상 코딩이 가능하다.
button2.setOnAction(e ->
{
System.out.println("CLICKED Button 2");
System.out.println("Amazing JavaFx");
});
각 컴포넌트가 사용가능한 메서드가 수백가지다. 그런데 이 수백가지 메서드를 다 사용하는게 아니니까 필요한 기능이 있다면 그때그때 찾아서 사용할 수 있도록 한다. 항상 느끼지만 무언가를 외워서 하려고 하면 한계가 금방 오니까 문제가 생겼을 때 해결하는 도구로써 API 를 바라봐야 한다. 그러기 위해서는 단순히 암기를 안하면 되는게 아니라 어떻게 검색하고 찾아야 하는지? 어떤 문제에 적합한 API 인지를 평소에 알아두고 있어야 한다.
다음 포스팅에서 더 많은 컴포넌트 들을 다루도록 한다.