Gráficos
Ya que nuestra
LibretaDirecciones incluye las fechas de nacimiento de cada persona, vamos a generar un informe que me permita mostrar en forma de gráfico de barras la cantidad de personas que nacen en cada mes del año.
La vista
Para ello, crearemos una nueva vista llamada
VistaEstadisticas.fxml dentro del paquete
view y, desde
Scene Builder, le aplicaremos las siguientes características:
- En la sección layout(derecha) del AnchorPane, establece Pref Width y Pref Height a 620x450.
- Desde la sección Charts (izquierda) añade un BarChart dentro del AnchorPane.
- Haz clic derecho sobre el BarChart y selecciona Fit to parent.
- Guarda el archivo.
El controlador
Para controlar la vista, crea una nueva clase Java llamada
VistaEstadisticasController dentro del paquete
view con el siguiente código:
public class VistaEstadisticasController {
@FXML
private BarChart<String, Integer> graficoBarras;
@FXML
private CategoryAxis ejeX;
@FXML
private NumberAxis ejeY;
private ObservableList<String> nombreMeses = FXCollections.observableArrayList();
//Se invoca justo después de que se ha cargado el archivo FXML
@FXML
private void initialize() {
//Array de nombre de meses
String[] meses = {"Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"};
//Los convierto a lista obervable
nombreMeses.addAll(Arrays.asList(meses));
//Asigno los nombres de meses a categorías
ejeX.setCategories(nombreMeses);
//Etiquetas de los ejes
ejeX.setLabel("Mes de nacimiento");
ejeY.setLabel("Número de personas");
}
//Set mes de cada persona para el eje Y
public void setDatosPersona(List<Persona> personas) {
//Array con cantidad de personas por mes de nacimiento
int[] numMes = new int[12];
for (Persona p : personas) {
int mes = p.getFechaDeNacimiento().getMonthValue() - 1;
numMes[mes]++;
}
//Genero la serie
XYChart.Series<String, Integer> series = new XYChart.Series<>();
series.setName("Mes de nacimiento");
for (int i = 0; i < numMes.length; i++) {
series.getData().add(new XYChart.Data<>(nombreMeses.get(i), numMes[i]));
}
//Añado la serie al gráfico
graficoBarras.getData().add(series);
}
}
Como vemos, el controlador necesitará acceso a dos elementos de nuestro archivo FXML:
- graficoBarras, que tiene los tipos String (meses en eje X) e Integer (número de personas en ese mes en el eje Y)
- ejeX: Lo usaremos para añadir las nombres de los meses
El método
initialize() rellena el eje X con la lista de todos los meses. El método
setDatosPersona(...)será llamado por la clase
LibretaDirecciones para establecer los datos de personas, recorriendo todas ellas y contando los nacimientos por mes, que luego añadirá a un nuevo XYChart.Data (una barra en el gráfico) para cada mes a la serie de datos. Para finalizar, añado la serie al gráfico.
Conexión de la vista a su controlador
Como en anteriores ocasiones, abre
VistaEstadisticas.fxml en Scene Builder y realiza las siguientes acciones:
En
Controller (izquierda) selecciona
VistaEstadisticasController como
Controller class.
En Hierarchy (izquierda), selecciona el
BarChart y, en
Properties(derecha) escribe
fecha de nacimientocomo
Title.
En Hierarchy (izquierda), selecciona el
BarChart y, en
Code (derecha) asigna
graficoBarras como
fx:id.
En Hierarchy (izquierda), selecciona
CategoryAxis dentro de
BarChart y, en
Code (derecha) asigna
ejecomo
fx:id.
Conexión del controlador con la clase principal
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
LibretaDirecciones (declarando primero la variable
vistaEstadisticas de tipo
AnchorPane):
public void crearGrafico() {
//Cargo la vista estadísticas
FXMLLoader loader = new FXMLLoader();
URL location = LibretaDirecciones.class.getResource("/view/VistaEstadisticas.fxml");
loader.setLocation(location);
try {
vistaEstadisticas = loader.load();
} catch (IOException ex) {
Logger.getLogger(LibretaDirecciones.class.getName()).log(Level.SEVERE, null, ex);
}
//Inicializo un nuevo escenario y asigno el principal
Stage escenarioEstadisticas = new Stage();
escenarioEstadisticas.setTitle("Estadísticas");
escenarioEstadisticas.initModality(Modality.WINDOW_MODAL);
escenarioEstadisticas.initOwner(escenarioPrincipal);
//Cargo la escena que contiene ese layout de estadisticas
Scene escena = new Scene(vistaEstadisticas);
escenarioEstadisticas.setScene(escena);
//Asigno el controlador
VistaEstadisticasController controller = loader.getController();
controller.setDatosPersona(datosPersona);
//Muestro el escenario
escenarioEstadisticas.show();
}
Asignar la acción al menú
En
VistaPrincipal.fxml, añade un nuevo menú llamado
Estadísticas con un
MenuItem llamado
Gráfico.
En
VistaPrincipalController, añade el siguiente método para controlar esa acción de menú:
//Gráfico
@FXML
private void grafico() {
libretaDirecciones.crearGrafico();
}
Por último, en
VistaPrincipal.fxml, selecciona el
MenuItem Gráficode
Estadísticas y, en
Code (derecha), selecciona
grafico para el campo
On Action.
Más información sobre gráficos con JavaFX
AQUÍ.
Informes en PDF
Para generar un informe en PDF de nuestra libreta de direcciones, haremos uso de librería externa
Apache PDFBox.
Para ello, debemos acceder a la sección
Downloads de la página y descargarnos el fichero
pdfbox-app-2.0.13.jar o la versión más reciente que encontremos.
Instalación de la librería
Una vez descargada la librería, podemos añadirla a nuestro proyecto
NetBeans en las
Properties de nuestro proyecto (botón derecho), accediendo a la sección
Libraries y añadiendo la ruta de nuestro archivo
jar mediante el botón
Add JAR/Folder..
Creación del método en la clase principal
De este modo, ya podremos crear un nuevo método en la clase principal
LibretaDirecciones que genere un PDF básico con el contenido de nuestra libreta.
public void crearPDF() throws IOException{
//Creo un nuevo documento, una página y la añado
PDDocument documento = new PDDocument();
PDPage pagina = new PDPage();
documento.addPage(pagina);
documento.getPage(0);
//Inicio un nuevo stream de contenido
PDPageContentStream contentStream = new PDPageContentStream(documento, pagina);
//Establezco la posición Y de la primera líena y el tipo de fuente
int linea = 700;
contentStream.setFont(PDType1Font.TIMES_ROMAN, 12);
//Recorro la lista de personas
List<Persona> personas = datosPersona;
for (Persona p : personas) {
//Inicio un nuevo texto y escribo los datos
contentStream.beginText();
contentStream.newLineAtOffset(25, linea);
contentStream.showText(p.getNombre()+" ");
contentStream.showText(p.getApellidos()+" ");
contentStream.showText(p.getDireccion()+" ");
contentStream.endText();
//Cambio de línea
linea -= 25;
}
//Cierro el content stream
contentStream.close();
//INicio el file chooser
FileChooser fileChooser = new FileChooser();
//Filtro para la extensión
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(
"PDF files (*.pdf)", "*.pdf");
fileChooser.getExtensionFilters().add(extFilter);
//Muestro el diálogo de guardar
File archivo = fileChooser.showSaveDialog(getPrimaryStage());
if (archivo != null) {
//Me aseguro de que tiene la extensión correcta y si no la cambio
String extension = "";
if (!archivo.getPath().endsWith(extension)){
extension = ".pdf";
}
//Escribo en el archivo y lo cierro
archivo = new File(archivo.getPath() + extension);
documento.save(archivo);
documento.close();
}
//Abro el archivo en el visor de PDF del sistema
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().open(archivo);
}
catch (IOException ex) {
}
}
}
Creación de la acción de menú en el controlador de la vista
Solo faltarían dos cosas: añadir un método para la acción del menú que generará un PDF en
VistaPrincipalController:
//PDF
@FXML
private void pdf() throws IOException {
libretaDirecciones.crearPDF();
}
Conexión del controlador a la vista
Y añadir un
MenuItem llamado PDF dentro del
Menu Estadísticas al que le asignaremos como
On Action el método
pdf.
El PDF aquí generado es bastante simple y muestra las opciones básicas. Puedes seguir
ESTE TUTORIAL para generar PDFs más completos.