Учебник по JavaFX (Русский)

Часть 6: Статистическая диаграмма

Screenshot AddressApp Part 6

Часть 6: Содержание

  • Создание статистической диаграммы для показа распределения дней рождений по месяцам.

Статистика дней рождений

Каждый адресат в нашем приложении AddressApp имеет свой день рождения. Было бы неплохо видеть некоторую статистику о том, когда они празднуют свои дни рождения.

Мы будем использовать столбцовую диаграмму, один столбец будет символизировать один месяц. Каждый столбец будет показывать, сколько дней рождений приходится на его месяц.

FXML-представление статистики

  1. Начните с создания внутри пакета ch.makery.address.view файла BirthdayStatistics.fxml (правый клик на пакете | New | other… | New FXML Document).
    Birthday Statistics FXML

  2. Откройте файл BirthdayStatistics.fxml в приложении Scene Builder.

  3. Выберите корневой компонент AnchorPane. Во вкладке Layout установите значение Pref Width в 620, а Pref Height в 450.

  4. Добавьте на панель AnchorPane компонент BarChart.

  5. Кликните правой кнопкой мышки на добавленном BarChart и выберите Fit to Parent.

  6. Сохраните fxml-файл, перейдите в Eclipse и обновите проект.

Перед тем, как вернутся в приложение Scene Builder, давайте создадим контроллер и в классе MainApp свяжем всё между собой.

Класс-контроллер статистики

В пакете ch.makery.address.view создайте класс 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 для каждого месяца.
        // Добавляем его в серии.
        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-файла:

    • barChart использует типы данных String и Integer. Тип данных String отображает название месяцев на оси X, а тип данных Integer - количество записей в конкретном месяце.
    • Ось xAxis мы используем для добавления названий месяцев.
  2. Метод initialize() заполняет ось X строковыми значениями названий всех месяцев.

  3. Метод setPersonData(...) будет доступен классу MainApp для передачи данных об адресатах. Он проходится по всем адресатам и подсчитывает количество дней рождений в каждом месяце. Потом он добавляет XYChart.Data для каждого месяца в серию данных XYChart.Series. Каждый объект XYChart.Data будет представлять один столбец диаграммы.


Соединяем представление и контроллер

  1. В приложении Scene Builder откройте файл BirthdayStatistics.fxml.

  2. Во вкладке Controller установите в качестве контроллера BirthdayStatisticsController.

  3. Выберите компонент BarChart и в свойстве fx:id установите значение barChart.

  4. Выберите CategoryAxis и в свойстве fx:id установите значение xAxis. Category Axis

  5. Для будущей стилизации, во вкладке Properties вы можете добавить название своей диаграммы.


Соединяем представление/контроллер с классом MainApp

Для отображения статистики дней рождений мы будем использовать тот же механизм, что ранее использовали для отображения окна редактирования данных об адресатах.

Добавьте следующий метод в класс MainApp:

/**
 * Открывает диалоговое окно для вывода статистики дней рождений.
 */
public void showBirthdayStatistics() {
    try {
        // Загружает fxml-файл и создаёт новую сцену для всплывающего окна.
        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 и создайте меню Statistics с единственным пунктом меню Show Statistics:

Show Statistics Menu

Выберите пункт меню Show Statistics и в качестве значения свойства On Action установите метод handleShowBirthdayStatistics.

Show Statistics On Action

Перейдите в среду разработки Eclipse, обновите проект и протестируйте ваше приложение.


Больше информации о диаграммах в JavaFX

Хороший источник для получения дополнительной информации о диаграммах в JavaFX - официальный учебник от Oracle Работа с диаграммами в JavaFX

Что дальше?

В последней, 7-й части учебника мы наконец развернём наше приложение (то есть, упакуем и доставим приложение нашим пользователям).

Вам могут быть интересны также некоторые другие статьи