JavaFX 튜토리얼

6부: 통계 차트

Screenshot AddressApp Part 6

6부 주제

  • 통계 차트를 만들어 생일 분포 보여주기

생일 통계

AddressApp의 모든 연락처에는 생일이 있습니다. 생일을 기념할 때 이에 대한 통계를 보여주면 더 좋을 것 같습니다.

우리는 바 차트를 사용할 겁니다. 각 바는 연락처에 있는 생일을 월별로 보여줍니다.

FXML View 통계

  1. ch.makery.address.view 패키지 (* 마우스 오른쪽 클릭 | New | other… | New FXML Document*)에 BirthdayStatistics.fxml 파일을 만듭니다.
    Birthday Statistics FXML

  2. Scene Builder로 BirthdayStatistics.fxml 파일을 엽니다.

  3. 상위 레이아웃인 AnchorPane을 선택합니다. Layout 그룹에서 Pref Width 값을 620로, Pref Height 값을 450으로 설정합니다.

  4. AnchorPane에 BarChart*를 추가합니다.

  5. BarChart에서 마우스 오른쪽 클릭 후 Fit to Parents를 선택합니다.

  6. FXML 파일을 저장합니다. Eclipse에서 프로젝트를 새로고침합니다.

Scene Builder로 돌아가기 전에 먼저 컨트롤러를 만들고 MainApp에서 모든 것을 연결할 겁니다.

통계 컨트롤러

뷰 패키지인 ch.makery.address.view에 새로운 Java 클래스 BirthdayStatisticsController.java를 만듭니다.

무슨 코드인지 설명하기 전에 컨트롤러 클래스 전체를 보여드리겠습니다:

BirthdayStatisticsController.java
package ch.makery.address.view;

import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.XYChart;
import ch.makery.address.model.Person;

/**
 * 생일 통계 뷰에 대한 컨트롤러
 *
 * @author Marco Jakob
 */
public class BirthdayStatisticsController {

    @FXML
    private BarChart<String, Integer> barChart;

    @FXML
    private CategoryAxis xAxis;

    private ObservableList<String> monthNames = FXCollections.observableArrayList();

    /**
     * 컨트롤러 클래스를 초기화한다. 이 메서드는 FXML 파일이 로드된 후 자동으로 호출된다.
     */
    @FXML
    private void initialize() {
        // 영어 월 이름을 배열로 가져온다.
        String[] months = DateFormatSymbols.getInstance(Locale.ENGLISH).getMonths();
        // 리스트로 변환하고 나서 ObservableList에 추가한다.
        monthNames.addAll(Arrays.asList(months));

        // 수평축에 월 이름을 카테고리로 할당한다.
        xAxis.setCategories(monthNames);
    }

    /**
     * 통계에 보여줄 연락처를 설정한다.
     *
     * @param persons
     */
    public void setPersonData(List<Person> persons) {
    	// 연락처 생일의 월 개수를 누적한다.
        int[] monthCounter = new int[12];
        for (Person p : persons) {
            int month = p.getBirthday().getMonthValue() - 1;
            monthCounter[month]++;
        }

        XYChart.Series<String, Integer> series = new XYChart.Series<>();

        // 월별로 XYChart.Data 객체를 만든다. series에 추가한다.
        for (int i = 0; i < monthCounter.length; i++) {
        	series.getData().add(new XYChart.Data<>(monthNames.get(i), monthCounter[i]));
        }

        barChart.getData().add(series);
    }
}

원리

  1. 컨트롤러는 FXML 파일에서 엘리먼트 2개에 접근해야 합니다:

    • barChart: String과 Integer 타입을 가집니다. String은 xAxis에서 월로 사용되고 Integer는 그 달의 연락처 개수에 사용됩니다.
    • xAxis: 이걸로 월 String을 추가할 겁니다.
  2. initialize() 메서드는 모든 월 리스트를 xAxis의 값으로 채웁니다.

  3. setPersonData(...) 메서드는 MainApp 클래스에서 연락처 데이터를 설정하기 위해 이용될 겁니다. 모든 연락처를 순회해서 월별로 생일 개수를 셉니다. 그 후 series 데이터에 모든 달의 XYChart.Data를 추가합니다. 각 XYChart.Data 객체는 차트에서 바 하나를 나타냅니다.


뷰와 컨트롤러 연결하기

  1. Scene Builder로 BirthdayStatistics.fxml 파일을 엽니다.

  2. Controller 그룹에서 BirthdayStatisticsController를 controller로 설정합니다.

  3. BarChart를 선택 후 fx:id 프로퍼티로 barChart를 고릅니다 (Code 그룹에서).

  4. CategoryAxis를 선택하고 fx:id 프로퍼티로 xAxis를 고릅니다.
    Category Axis

  5. BarChart의 타이틀 (Properties 그룹에서)을 추가할 수 있습니다.


뷰/컨트롤러를 MainApp으로 연결하기

우리는 생일 통계의 동일한 메커니즘을 연락처 변경 다이얼로그에 사용할 겁니다.

다음 메서드를 MainApp 클래스에 추가하세요:

/**
 * 생일 통계를 보여주기 위해 다이얼로그를 연다.
 */
public void showBirthdayStatistics() {
    try {
        // FXML 파일을 불러와서 팝업의 새로운 Stage를 만든다.
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(MainApp.class.getResource("view/BirthdayStatistics.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Stage dialogStage = new Stage();
        dialogStage.setTitle("Birthday Statistics");
        dialogStage.initModality(Modality.WINDOW_MODAL);
        dialogStage.initOwner(primaryStage);
        Scene scene = new Scene(page);
        dialogStage.setScene(scene);

        // 연락처를 컨트롤러에 설정한다.
        BirthdayStatisticsController controller = loader.getController();
        controller.setPersonData(personData);

        dialogStage.show();

    } catch (IOException e) {
        e.printStackTrace();
    }
}

모든 준비가 끝났습니다. 하지만 실제로 새로운 showBirthdayStatistics() 메서드를 호출하지 않습니다. 운이 좋게도 RootLayout.fxml에는 메뉴가 있습니다.

생일 차트 메뉴 보여주기

RootLayoutController에 show birthday statistics 메뉴 아이템 클릭을 제어하는 다음 메서드를 추가합니다:

/**
 * 생일 차트를 연다.
 */
@FXML
private void handleShowBirthdayStatistics() {
  mainApp.showBirthdayStatistics();
}

이제 Scene Builder로 RootLayout.fxml 파일을 엽니다. Show Statistics MenuItem을 포함한 Statistics Menu를 만듭니다:

Show Statistics Menu

Show Statistics MenuItem을 선택하고 On Action을 handleShowBirthdayStatistics로 고릅니다 (Code 그룹에서).

Show Statistics On Action

Eclipse로 가서 프로젝트를 새로고침한 후 테스트 하세요.


JavaFX 차트에 대한 자세한 정보

공식 Oracle 튜토리얼에 자세한 정보가 나와 있습니다: Working with JavaFX Charts.

다음 할 일은?

마지막 튜토리얼 7부에서는 마침내 우리 애플리케이션을 배포할 겁니다 (즉 패키징과 전달)

흥미로운 자료들