Ejemplo de calendario en JavaFX

No tenia mucho que hacer y vi que Java 7 trae un calendario (Swing), muy bonito, a mi gusto. En la noche tuve un poco de tiempo y quise crear el mio con JavaFX, pues aquí se los dejo y si lo pueden mejorar, pues agradecería enormemente lo compartieran.

Si tienes consejos, sugerencias, dudas, etc. me dices ok... :P

FechaItem: Esta clase es la unidad de una fecha en un mes de un año (jajajaja). Como atributo publico obtiene un objeto tipo Date. Deje un evento de tipo onMouseClicked para ejemplificar donde pones código para meterlo en una base de datos o lo que se le antoje, en este caso solo cambia de color y te dice por consola que día pinchaste y si esta libre o con cita.

package calendarfx;

import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import java.util.Date;
import javafx.scene.paint.Color;
import java.util.Calendar;
import javafx.scene.control.Label;
import javafx.scene.shape.Rectangle;
import java.util.GregorianCalendar;
import javafx.scene.layout.Panel;
import javafx.scene.input.MouseEvent;

/**
 * @author Rodrigo Salado Anaya
 */

public class FechaItem extends CustomNode {

    /*atributos publicos*/
    public var fecha: Date;
    /*posibles colores de la fecha*/
    def libre: Color = Color.WHITE;
    def cita: Color = Color.LIGHTBLUE;
    /*estado de la fecha*/
    var estado: Boolean = true;
    /*colores de la celda*/
    var colorFill: Color = libre;
    def colorStroke: Color = Color.BLACK;
    /**/
    var calendario: Calendar;
    var fechaLabel: Label = Label {text: fechaToString() };
    /*marco de la celda*/
    public var marco: Rectangle = Rectangle {
                width: 15
                height: 15
                fill: bind colorFill
                stroke: colorStroke
                strokeWidth: 0.2
            }

    function fechaToString(): String {
        if (fecha == null) {
            calendario = new GregorianCalendar();
            return "";
        } else {
            calendario = new GregorianCalendar();
            calendario.setTime(fecha);
            return calendario.get(Calendar.DATE).toString();
        }
    }

    var panel: Panel = Panel {
                content: [marco, fechaLabel]
                onLayout: function (): Void {
                    panel.positionNode(marco, 0, 0);
                    var w = fechaLabel.getPrefWidth(0);
                    var h = fechaLabel.getPrefHeight(0);
                    panel.layoutNode(fechaLabel, (marco.width - w) / 2, (marco.height - h) / 2, w, h);
                }
            }

    public override function create(): Node {
        return Group {
                    content: [panel]
                    onMouseClicked: function (e: MouseEvent): Void {
                        estado = not estado;
                        colorFill = if (estado) libre
                                else cita;
                        println("{fecha}:{if (estado) " Libre!!!" else " Cita"}");
                    }
                };
    }

}

MesItem: Representa el mes [0:Enero, 1:Febrero... 11:Diciembre] del año deseado. Recibe de manera publica un año como anio y un mes, tail y panel son los encargado de darle forma de cuadricula, aun así la función generaMes() es la encargada de generar los FechaItem con los datos deseados.

package calendarfx;

import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.geometry.HPos;
import javafx.scene.layout.Panel;
import javafx.scene.layout.Tile;
import javafx.scene.shape.Rectangle;
import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * @author Rodrigo Salado Anaya
 */

public class MesItem extends CustomNode {

    /*atributos publicos*/
    public var anio: Integer;
    public var mes: Integer;
    /*conjunto de fechas*/
    var mesCalendario: FechaItem[];
    var mesArr = [
                "ENERO", "FEBRERO", "MARZO", "ABRIL",
                "MAYO", "JUNIO", "JULIO", "AGOSTO",
                "SEPTIEMBRE", "OCTUBRE", "NOVIEMBRE", "DICIEMBRE"
            ];
    var mesLabel = Label {text: mesArr[mes] textFill: Color.BLACK font: Font {size: 14 } };
    var dias = [
                Label {text: "L" textFill: Color.DODGERBLUE },
                Label {text: "M" textFill: Color.DODGERBLUE },
                Label {text: "M" textFill: Color.DODGERBLUE },
                Label {text: "J" textFill: Color.DODGERBLUE },
                Label {text: "V" textFill: Color.DODGERBLUE },
                Label {text: "S" textFill: Color.DODGERBLUE },
                Label {text: "D" textFill: Color.DODGERBLUE }
            ];

    function generaMes(): FechaItem[] {
        /*asignamos la fecha deseada*/
        var c: Calendar = new GregorianCalendar();
        c.set(anio, mes, 1);
        /*generamos las fechas vacias del inicio*/
        var fechasVacias = c.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY;
        if (fechasVacias < 0) {
            fechasVacias = fechasVacias + 7;
        }
        mesCalendario = for (n in [1..fechasVacias]) {
                    FechaItem {};
                }
        /*generamos las fechas del mes*/
        while (Integer.valueOf(c.get(Calendar.MONTH)) == mes) {
            insert FechaItem {fecha: c.getTime() } into mesCalendario;
            c.add(Calendar.DATE, 1);
        }
        /*generamos las fechas vacias del final del mes*/
        for (n in [mesCalendario.size()..41]) {
            insert FechaItem {} into mesCalendario;
        }
        /*return; regresamos todos los items de las fechas*/
        mesCalendario;
    };

    var marco: Rectangle = Rectangle {
                width: 170, height: 162
                fill: Color.WHITE;
                stroke: Color.BLACK;
            }
    /*acomoda los items de las fechas, y las etiquetas de los días*/
    var tail: Tile = Tile {
                columns: 8
                hgap: 5
                vgap: 5
                hpos: HPos.CENTER
                content: [dias, generaMes()]
            }
    /*mmmmm... a mi me gusta mucho usar 'panel' pero aqui lo use para acomodar todo*/
    var panel: Panel = Panel {
                content: [marco, mesLabel, tail]
                onLayout: function (): Void {
                    panel.positionNode(marco, 0, 0);
                    var w = mesLabel.getPrefWidth(0);
                    var h = mesLabel.getPrefHeight(0);
                    var x = (marco.width - w) / 2;
                    var y = 2;
                    panel.layoutNode(mesLabel, x, y, w, h);
                    w = 150;
                    h = 500;
                    x = (marco.width - w) / 2;
                    y = 20;
                    panel.layoutNode(tail, x, y, w, h);
                }
            }

    public override function create(): Node {
        return Group {
                    content: [panel]
                };
    }

}

Por ejemplo para generar el mes de junio del año 2010 basta con crear un nodo así:

MesItem {anio: 2010 mes: 0 }

Y si quisiéramos generar todos los meses del 2010, podríamos usar algo así, donde tail se encarga de formar la cuadrilla:

var mesesCalendario: MesItem[];

function generaMeses(): MesItem[] {
    mesesCalendario = for (n in [0..11]) {
                MesItem {anio: 2010 mes: n }
            }
}

var tail: Tile = Tile {
            columns: 4
            hgap: 5
            vgap: 5
            hpos: HPos.CENTER
            content: [generaMeses()]
        }

O crear un CustomNode como este:

public class AnioItem extends CustomNode {

    public var anio: Integer;
    var mesesCalendario: MesItem[];

    function generaMeses(): MesItem[] {
        mesesCalendario = for (n in [0..11]) {
                    MesItem {anio: anio mes: n }
                }
    }

    var tail: Tile = Tile {
                columns: 4
                hgap: 5
                vgap: 5
                hpos: HPos.CENTER
                content: [generaMeses()]
            }

    public override function create(): Node {
        return Group {
                    content: [tail]
                };
    }

}

Entonces solo necesitaríamos crear un nodo así:

AnioItem{anio:2010}

Nota: http://www.javahispano.org/forum/j2se/es/como_crear_un_calendario_en_java/ , http://learnjavafx.typepad.com/weblog/2008/03/a-javafx-script.html y http://kenai.com/projects/jfxcalendarpicker/pages/Home , la verdad no le eche una leída intensa a la clase Calendar y todas las demás, como dije es solo un ejemplo, ya que se ve mucho código, y es muy posible que se pueda hacer mas sencillo y eficiente.
Nos leemos pronto y buen mes para todos :P

AdjuntoTamaño
fullCal.png68.09 KB
oneCal.png18.89 KB

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de Marce

Muy bien

Me agrada mucho que te interesaras en probar y hacer el calendario en JFX, yo nunca he usado JFX pero al ver el código entiendo la lógica sin saber exactamente la sintaxis, muy buen aporte. Sobre todo me agrada la vista que le da JFX a la interfaz es muy buena.

exelente trabajo, ojalá

exelente trabajo, ojalá pudieras mostrar algunos otros proyectos con javaFx para que los que nos iciamos en él, puédamos aprender. gran aporte

Fantastico aporte!!

Fantastico aporte!! Enhorabuena y muchas gracias!!