Tutorial JavaFX (Español)

Parte 6: Gráficos estadísticas

Screenshot AddressApp Part 6

Contenidos en Parte 6

  • Creando un Gráfico estadístico para mostrar la distribución de meses de nacimiento.

Estadísticas sobre fecha de nacimiento

Las personas en nuestra libreta de direcciones tienen una fecha de nacimiento. ¿No sería bonito tener algunas estadísticas sobre los meses en que celebran el cumpleaños?.

Usaremos un Gráfico de barras conteniendo una barra para cada mes. Cada barra mostrará cuantas personas en nuestra libreta cumplen años ese mes en particular.

La vista FXML de estadísticas

  1. Empezamos creando un archivo BirthdayStatistics.fxml dentro del paquete ch.makery.address.view (Clic derecho | New | Other… | New FXML Document).
    Birthday Statistics FXML

  2. Abre el archivo BirthdayStatistics.fxml en Scene Builder.

  3. Elige el panel raíz AnchorPane. En la sección de Layout establece la anchura y altura preferidas (Pref Width, Pref Height) en 620 y 450 respectivamente.

  4. Añade un componente BarChart al AnchorPane.

  5. Clic derecho sobre el elemento BarChart y elige Fit to Parent.

  6. Guarda el archivo FXML, vuelve a Eclipse y refresca el proyecto (F5).

Antes de volver a Scene Builder vamos a crear el controlador y a realizar las conexiones necesarias en nuestra MainApp.

El controlador para las estadísticas

En el paquete de vistas ch.makery.address.view crea una nueva clase Java denominada BirthdayStatisticsController.java.

Veamos primero el controlador completo antes de explicarlo:

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;

/**
 * The controller for the birthday statistics view.
 * 
 * @author Marco Jakob
 */
public class BirthdayStatisticsController {

    @FXML
    private BarChart<String, Integer> barChart;

    @FXML
    private CategoryAxis xAxis;

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

    /**
     * Initializes the controller class. This method is automatically called
     * after the fxml file has been loaded.
     */
    @FXML
    private void initialize() {
        // Get an array with the English month names.
        String[] months = DateFormatSymbols.getInstance(Locale.ENGLISH).getMonths();
        // Convert it to a list and add it to our ObservableList of months.
        monthNames.addAll(Arrays.asList(months));
        
        // Assign the month names as categories for the horizontal axis.
        xAxis.setCategories(monthNames);
    }

    /**
     * Sets the persons to show the statistics for.
     * 
     * @param persons
     */
    public void setPersonData(List<Person> persons) {
    	// Count the number of people having their birthday in a specific month.
        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<>();
        
        // Create a XYChart.Data object for each month. Add it to the series.
        for (int i = 0; i < monthCounter.length; i++) {
        	series.getData().add(new XYChart.Data<>(monthNames.get(i), monthCounter[i]));
        }
        
        barChart.getData().add(series);
    }
}

Como funciona el controlador

  1. El controlador necesitará acceso a dos elementos de nuestro archivo FXML:

    • barChar: Tiene los tipos String e Integer. El tipo String se utiliza para el mes en el eje-X y el tipo Integer se utiliza para el número de personas en un mes determinado.
    • xAxis: Lo usaremos para añadir las nombres de los meses
  2. El método initialize() rellena el eje-X con la lista de todos los meses.

  3. El método setPersonData(...)será accedido por la clase MainApp para establecer los datos de personas. Este método recorre todas las personas y cuenta los nacimientos por mes. Entonces añade XYChart.Data para cada mes a las series de datos. Cada objeto XYChart.Data representará una barra en el gráfico.


Conectando vista y controlador

  1. Abre BirthdayStatistics.fxml en Scene Builder.

  2. En la sección Controller pon BirthdayStatisticsController como controlador.

  3. Selecciona el componente BarChart y pon barChart en la propiedad fx:id (sección Code).

  4. Elige el componente CategoryAxis y pon xAxis como propiedad fx:id.
    Category Axis

  5. Puedes añadir un título al componente BarChart (en Properties) para mejorar la apariencia.


Conectando vista y controlador con MainApp

Para el gráfico de estadísticas usaremos el mismo mecanismo que utilizamos para el diálogo de edición de personas, una ventana de diálogo emergente.

Añade el siguiente método a tu clase MainApp:

/**
 * Opens a dialog to show birthday statistics.
 */
public void showBirthdayStatistics() {
    try {
        // Load the fxml file and create a new stage for the popup.
        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);

        // Set the persons into the controller.
        BirthdayStatisticsController controller = loader.getController();
        controller.setPersonData(personData);

        dialogStage.show();

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

Todo está dispuesto, pero todavía no tenemos nada para invocar al nuevo método showBirthdayStatistics(). Afortunadamente ya tenemos un menú en en la vista RootLayout.fxml que puede ser usado para estos fines.

Muestra el menú de estadísticas de cumpleaños

En tu RootLayoutController añade el siguiente método para gestionar las pulsaciones sobre el ítem de menú Show Statistics:

/**
 * Opens the birthday statistics.
 */
@FXML
private void handleShowBirthdayStatistics() {
  mainApp.showBirthdayStatistics();
}

Ahora, abre RootLayout.fxml en Scene Builder. Crea el menú Statistics con un ítem denominado Show Statistics:

Show Statistics Menu

Elige el ítem de menú Show Statistics y establece handleShowBirthdayStatistics en su campo On Action (sección Code).

Show Statistics On Action

Vuelve a Eclipse, refresca el proyecto y pruébalo.


Más información sobre gráficos JavaFX

Un buen sitio para obtener más información es el tutorial oficial de Oracle: Working with JavaFX Charts.

¿Qué es lo siguiente?

En la última parte del tutorial, Part 7, vamos por fin a desplegar nuestra aplicación (es decir, la empaquetaremos y la haremos llegar a los usuarios).

Otros artículos que podrías encontrar de interés