Ejemplo sacado de los tutoriales de JavaFX
Pintar un gráfico “a pelo”
/*
* Main.fx
* @author: juantxu
* Created on 23-jul-2009, 7:46:27
* @copyleft
*/
package guitest1;
import javafx.scene.Scene;
import javafx.scene.layout.LayoutInfo;
import javafx.scene.layout.HBox;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;
import javafx.stage.Stage;
def values = [
BarChart.Data { value: 14 category: "Pedro" }
BarChart.Data { value: 19 category: "María" }
BarChart.Data { value: 14 category: "Eustaquio" }
BarChart.Data { value: 213 category: "Zeus" }
BarChart.Data { value: 149 category: "Esquilo" }
BarChart.Data { value: 306 category: "Homero" }
BarChart.Data { value: 167 category: "Baco" }
];
Stage {
title: "Mi Gráfico de barras"
scene: Scene {
width: 580
height: 420
content:
HBox{
content:[
BarChart {
title: "Estadisticas de accesos"
layoutInfo: LayoutInfo {width: 580}
data: BarChart.Series {
name: "Accesos"
data: values
}
categoryAxis: CategoryAxis {
categories: for (value in values) value.category
}
valueAxis: NumberAxis {
lowerBound: 0
upperBound: 340
tickUnit: 20
}
}
]
}
}
}
Y esto se ve tal que así:
Pero este ejemplo es un poco pobre. ¿No puedo leer los valores desde un XML? Vamos a probarlo.
Para empezar decirte que vas a necesitar JDOM para parsear el XML. La idea es tener unas clases java que me lea el xml y que me lo sirva en forma de un arraylist que javaFX usará como origen de datos.
Pongamos que tenemos este XML con pares de datos : /tmp/datos.xml
<?xml version="1.0"?>
<datos tipo="clave y valor">
<par>
<clave>Uria</clave>
<valor>10</valor>
</par>
<par>
<clave>Cafe</clave>
<valor>12</valor>
</par>
<par>
<clave>te aromatico</clave>
<valor>24</valor>
</par>
<par>
<clave>kawa</clave>
<valor>55</valor>
</par>
<par>
<clave>limon</clave>
<valor>18</valor>
</par>
<par>
<clave>te</clave>
<valor>12</valor>
</par>
</datos>
Lo que vamos a hacer es un DTO valorYSerie.java que contendrá cada valor y su serie
valorYSerie.java
package net.juantxu.barcharXml.datos;
/**
*
* @author juantxu
* @version 1.0
* @date 25/07/2009
*/
public class valorYSerie {
private String serie;
private int valor;
public String getSerie() {
return serie;
}
public void setSerie(String serie) {
this.serie = serie;
}
public int getValor() {
return valor;
}
public void setValor(int valor) {
this.valor = valor;
}
}
Por otra parte vamos a definir una interfaz que nos servirá para implementar después el lector desde XML . valorYSerieDAO.java
package net.juantxu.barcharXml.datos;
import java.util.List;
/**
*
* @author juantxu
*/
public interface valorYSerieDAO {
List<valorYSerie> getValores(String url);
}
Por fin el parseador propiamente dicho
package net.juantxu.barcharXml.datos;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;
/**
*
* @author juantxu
*/
public class valorYSerieDAOXML implements valorYSerieDAO{
ArrayList valoresYSeries;
@Override
public List<valorYSerie> getValores(String url) {
valoresYSeries = new ArrayList();
try {
SAXBuilder builder=new SAXBuilder(false);
//usar el parser Xerces y no queremos
//que valide el documento
Document doc=builder.build(url);
//construyo el arbol en memoria desde el fichero
// que se lo pasaré por parametro.
Element raiz=doc.getRootElement();
//cojo el elemento raiz
//todos los hijos que tengan como nombre
List pares=raiz.getChildren("par");
Iterator i = pares.iterator();
while (i.hasNext()){
valorYSerie par = new valorYSerie();
Element e= (Element)i.next();
// cada par clave /valor se mete en un bean y este a su vez en la lista
Element clave =e.getChild("clave");
Element valor =e.getChild("valor");
par.setSerie( clave.getText());
par.setValor(Integer.valueOf(valor.getText()));
valoresYSeries.add(par);
}
}catch (Exception e){
e.printStackTrace();
}
return this.valoresYSeries;
}
}
Ya lo tenemos todo, ahora sólo hace falta recoger los valores y pintar nuestro gráfico de barras:
/*
* Main.fx
* @author juantxu
* Created on 25-jul-2009, 8:38:00
*/
package barcharxml;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;
import net.juantxu.barcharXml.datos.valorYSerieDAOXML;
import net.juantxu.barcharXml.datos.valorYSerie;
var valoresDao = valorYSerieDAOXML{};
var valores = valoresDao.getValores("/tmp/pares.xml"); // la ubicación de nuestro xml
var barras: BarChart.Data[] =[];
// relleno los valores de las series/
for (par:valorYSerie in valores){
insert BarChart.Data {
value: par.getValor();
category: par.getSerie();
} into barras;
}
Stage {
title: "Grafico de barras"
width: 400
height: 400
scene: Scene {
content: [
BarChart { // grafico de barras
title: "Estadisticas de accesos"
width:300; // ancho del grafico
height:300; //
data: BarChart.Series {
name: "Nombre de la Serie"
data: barras
}
categoryGap: 10; // separacion entre barras
categoryAxis: CategoryAxis {
categories: for (value in barras) value.category
}
valueAxis: NumberAxis {
lowerBound: 0
upperBound: 50
//tickUnit: 50
}
}
]
}
}
y aquí tienes el resultado:
Pero todo esto es muy complicado. Para evitar todo este rollo tenemos el objeto HttpRequest y el objeto PullParser
Este ejemplo puede ser muy útil. La utilidad viene del hecho que lee de un xml externo por lo que los datos pueden ser actualizados facilmente.
/*
* Main.fx
* @author juantxu
* Created on 01-ago-2009, 12:27:52
* @copyleft
*/
package httprequestsample;
import javafx.data.pull.Event;
import javafx.data.pull.PullParser;
import javafx.data.xml.QName;
import java.io.InputStream;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;
import javafx.io.http.HttpRequest;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
var series:String[]; // esto lo usaré para pintar las claves de las series
var valoresDelGrafico: BarChart.Data[] =[]; // esto es un array de valores del grafico
var seriesDelGrafico: BarChart.Series[] = []; //esto es un array de series del grafico
var grafico: BarChart; // el grafico
var serie1: BarChart.Series; // la serie que meteré en el array de series una vez lleno
// declaro el grafico
grafico =BarChart {
categoryAxis: CategoryAxis {
categories: bind series // enlazo las categorías al array de las series
}
valueAxis: NumberAxis {
lowerBound: 0
upperBound: 25
tickUnit: 20
label:"Grafico de valores" // pongo una etiqueta
}
data: bind seriesDelGrafico // enlazo los datos a las series del grafico
}
/**
*esta es la función que parsea los datos que recibo del XML
*/
function parsea(input: InputStream) {
// Parsea propiamente dicho
def parser = PullParser { // defino el parseador y al final de la función ...
input: input
onEvent: function(event: Event) {
// los datos están en atributos de los elementos
// por lo que los leo de al iniciar el nodo
if (event.type == PullParser.START_ELEMENT) {
if(event.qname.name == "par" ) {
var clave = event.getAttributeValue(QName{name:"clave"}) as String;
var valor = event.getAttributeValue(QName{name:"valor"}) as String ;
insert BarChart.Data {
value: Number.parseFloat(valor)
} into valoresDelGrafico;
insert clave into series;
}
}
}
}
parser.parse(); // ... le digo que parsee
}
/**
* objeto HttpRequest qeu realizará la petición y invocará al parseador
*/
def recolectorDeDatos: HttpRequest = HttpRequest {
location: "http://en.juantxu.net/data/media/java/javafx/barchart/pares_atributos.xml"; // la url
onInput: function(is: java.io.InputStream) {
try {
parsea(is); // cuando le llegan los datos parsea.
} finally {
is.close();
}
}
onDone: function() {
pintaMiGrafico(); // cuando haya terminado pintará mi grafico
}
}
recolectorDeDatos.start();
/**
* función que pinta el grafico una vez terminado el parseo.
*/
function pintaMiGrafico(){
serie1 = BarChart.Series{data: valoresDelGrafico name: "Serie1"};
seriesDelGrafico= [serie1];
}
/**
* Texto que servirá de titulo.
*/
var titulo = Text {
font : Font {
size : 16
}
x: 200
y: 50
content: "Titulo del Grafico"
}
/**
* La escena
*/
Stage {
title: "Grafico desde un XML"
width: 500
height: 500
scene: Scene {
content: Group {
content: [titulo, grafico ];
}
}
}
Y esto es como quedaría este mismo ejemplo que recarga los datos cada vez que se lo pides: