Páginas

20/11/15

JCalendar Java Swing Tutorial.

JCalendar Java Swing Tutorial

Tutorial del JCalendar con ejemplos, Java Swing.




JUnit Assume Tutorial. Que mejor manera de controlar la fecha que un usuario ingresa que con un calendario en donde con un simple clic ya obtengamos Año, Mes y Día, en Java Swing no trae por defecto un componente que facilite este comportamiento, así que por eso hay que descargar una librería externa llamada JCalendar, dicha librería tiene varias funcionalidades, podemos elegir desde un calendario la fecha completa, la fecha de hoy, elegir una fecha maxima o minima para seleccionar, elegir solo un día, año o mes... En fin en este Tutorial de JCalendar vamos hacer varios ejemplos con las funcionalidades que ofrece utilizando el IDE JBoss Developer Studio o eclipse.



1. Descargar JCalendar.


Para realizar los ejemplos tenemos que descargar jcalendar-1.4.jar, y luego importarlo a nuestro classpath, puedes descargarlo desde aquí.

2. Crear proyecto Java.


Vamos a crear desde nuestro IDE un simple "Java Project" con el nombre de JCalendarDatoJava. Para eso recordamos que vamos a la opción de File> New> Java Project.
imagen New Project
Nuevo Java Project.
Una vez creado, en la carpeta src, creamos un paquete llamado datojava.jcalendar, y dentro del mismo vamos a crear la clase DJJCalendar en la cual vamos a desarrollar los ejemplos, aparte de eso vamos a crear otra clase llamada DJFechasEspInv que extiende de la interface IDateEvaluator en la cual vamos a desarrollar un ejemplo agregando fechas especiales/invalidas a nuestro JCalendar. Por ultimo importamos la librería jcalendar-1.4.jar al classpath de nuestro proyecto y esta es la estructura que debería tener hasta ahora nuestro proyecto:
Estructura JCalendar
Estructura JCalendar.

3. Ejemplo de JCalendar.


Hay varios componentes que ofrece esta librería, entre ellos esta el mas común JCalendar, que no es mas que un calendario en el cual podremos elegir una fecha:
JCalendar
JCalendar.
Este es el codigo para utilizar el componente JCalendar:
private JCalendar calendar;

// Instanciar Componente
calendar = new JCalendar();

// Ubicar y agregar al panel
calendar.setBounds...

panel.add(calendar);
  
A este JCalendar podemos agregarle/quitarle varias cosas, por ejemplo para agregar un boton que nos permita elegir la fecha de hoy:
  calendar.setTodayButtonVisible(true);
  
A ese boton podemos cambiarle el label (por defecto es "Hoy") de esta manera:
  calendar.setTodayButtonText("Hoy Día");
  
También podemos agregarle un boton para no seleccionar ninguna fecha:
  calendar.setNullDateButtonVisible(true);
  
Y de igual manera podemos cambiar el label por defecto ("Sin fecha"), así se ve el JCalendar con los botones:
JCalendar Botones
JCalendar Botones.
Si detallamos la imagen del calendario, podemos observar que muestra varios datos que a veces son innecesarios dependiendo de la aplicación, podemos hacer una que otra modificación quitandole o agregandole varias cosas.
Para quitar el numero de semanas:
  calendar.setWeekOfYearVisible(false);
  
JCalendar Sin Numero de semanas
JCalendar Sin Numero de semanas.
Para incrementar/decrementar la cantidad de caracteres que tiene el label de los días:
    calendar.setMaxDayCharacters(1);
  
JCalendar Sin Numero de semanas
JCalendar Primera Letra Del Día.
Cambiar color de letra de los días de semana, fin de semana o numero de día:
  // Cambiar color de letra del numero de día 
  calendar.setForeground(Color.GREEN);
  
  // Cambiar color de letra del dia domingo
  calendar.setSundayForeground(Color.BLUE);

  // Cambiar color de letra de semana
  calendar.setWeekdayForeground(Color.RED);
  
Establecer una fecha en el JCalendar:
  Calendar calendario = new GregorianCalendar(2014,5,10);
  calendar.setDate(calendario.getTime());
  
JCalendar establecer fecha
JCalendar establecer fecha.
Establecer la fecha maxima/minima que puede elegir un usuario:
  // Fecha minima seleccionable
  calendar.setMinSelectableDate(new Date());

  // Fecha maxima seleccionable
  calendar.setMaxSelectableDate(new Date());
  
Para establecer algunas fechas especiales o invalidas en el JCalendar, implementamos la clase DJFechasEspInv que creamos anteriormente, si por ejemplo queremos establecer como fecha especial el día 24 de diciembre y como fecha invalida el dia 01 de Enero:
package datojava.jcalendar;

import java.awt.Color;
import java.util.Calendar;
import java.util.Date;

import com.toedter.calendar.IDateEvaluator;

public class DJFechasEspInv implements IDateEvaluator {

 Calendar calendar = Calendar.getInstance();

 public DJFechasEspInv() {

 }

 @Override
 public boolean isSpecial(Date date) {
  calendar.setTime(date);
  return calendar.get(Calendar.MONTH) == Calendar.DECEMBER
    && calendar.get(Calendar.DAY_OF_MONTH) == 24;
 }

 @Override
 public Color getSpecialForegroundColor() {
  return Color.GREEN;
 }

 @Override
 public Color getSpecialBackroundColor() {
  return Color.WHITE;
 }

 @Override
 public String getSpecialTooltip() {
  return "Es Navidad";
 }

 @Override
 public boolean isInvalid(Date date) {
  calendar.setTime(date);
  return calendar.get(Calendar.MONTH) == Calendar.JANUARY
    && calendar.get(Calendar.DAY_OF_MONTH) == 01;
 }

 @Override
 public Color getInvalidForegroundColor() {
  return Color.WHITE;
 }

 @Override
 public Color getInvalidBackroundColor() {
  return Color.BLACK;
 }

 @Override
 public String getInvalidTooltip() {
  return "No es día Laborable";
 }
}
  
Explicando un poco el codigo, en la implementación del metodo boolean isSpecial(Date date) (18), obtenemos la fecha y verificamos si coincide con el día "24 de Diciembre", en caso de ser cierto, ese día tendrá la letra de color verde (Color getSpecialForegroundColor() (25)) y el fondo de color blanco (Color getSpecialBackroundColor() (30)), adicionalmente vamos agregarle el ToolTip con la descripción del día especial (String getSpecialTooltip() (35)), lo propio hacemos con el día invalido que en este caso es el día "01 de Enero" (boolean isInvalid(Date date) (40)), con la letra de color blanco (Color getInvalidForegroundColor() (47)), el fondo de color negro (Color getInvalidBackroundColor() (52)) y la descripción correspondiente (String getInvalidTooltip() (57)). Ahora tenemos que agregarle esta clase el calendar:
  calendar.getDayChooser().addDateEvaluator(new DJFechasEspInv());
  
Ya con eso funciona, pero en el caso de que necesitemos hacer algo como esto no creo que sea solo con una fecha, así que para agregar varias fechas se complica un poco, pero para todo hay solución. En la clase DJJCalendar tenemos que hacer dos metodos, uno en el cual crearemos una lista con todas las fechas especiales y otro con una lista de ToolTip por cada fecha especial, en el caso de que queramos agregar fechas invalidas creamos otro metodo adicional.
Metodo que retorna la lista de fechas especiales:
 public static List fechasEspeciales() {
  List fechas = new ArrayList();
  
  Calendar calendar = new GregorianCalendar(2015, Calendar.SEPTEMBER, 10);
  fechas.add(calendar);
  calendar = new GregorianCalendar(2015, Calendar.NOVEMBER, 10);
  fechas.add(calendar);
  calendar = new GregorianCalendar(2015, Calendar.NOVEMBER, 18);
  fechas.add(calendar);

  return fechas;
 }
  
Metodo que retorna la lista de ToolTip por cada fecha:
  public static List tipFechas() {
  List tips = new ArrayList();

  tips.add("Septiembre 10");
  tips.add("Noviembre 10");
  tips.add("Noviembre 18");

  return tips;
 }
 
Ahora en la implementación del metodo boolean isSpecial(Date date) recorremos la lista de fechas especiales y vamos pintando en el calendario las mismas:
 private int i = 0;
 
 @Override
 public boolean isSpecial(Date date) {
  calendar.setTime(date);
  for (i = 0; i < DJJCalendar.fechasEspeciales().size(); i++) {
   if (calendar.get(Calendar.MONTH) == DJJCalendar.fechasEspeciales()
     .get(i).get(Calendar.MONTH)
     && calendar.get(Calendar.DAY_OF_MONTH) == DJJCalendar
       .fechasEspeciales().get(i)
       .get(Calendar.DAY_OF_MONTH)) {
    return true;
   }
  }
  return false;
 }
  
Hacemos lo propio en el metodo String getSpecialTooltip(), obtenemos la descripción en la posición correspondiente y la pintamos en el calendario
 @Override
 public String getSpecialTooltip() {
  return DJJCalendar.tipFechas().get(i);
 }
  
Hay mas propiedades con las que podemos jugar, todo depende de lo que necesitemos para nuestra aplicación.

4. Ejemplo de JDateChooser.


El JDateChooser es mucho mas util, ya que este componente nos presenta un campo de texto con un boton al lado, que al presionarlo nos muestra el JCalendar descrito anteriormente, y al momento de seleccionar la fecha, la misma se muestra en el campo de texto:
JDateChooser
JDateChooser.
Este es el codigo para utilizar el componente JDateChooser:
 
private JDateChooser dateChooser;

// Instanciar Componente
dateChooser = new JDateChooser();

// Ubicar y agregar al panel
dateChooser.setBounds...

panel.add(calendar);
  
Obviamente a este componente también podemos modificarle sus propiedades, y como en si es otro JCalendar pero con un campo de texto, son practicamente las mismas propiedades, por ejemplo para obtener el JCalendar y aplicar las modificaciones anteriores necesitamos este codigo:
  dateChooser.getJCalendar();
  
En el campo de texto que ofrece JDateChooser el usuario puede ingresar la fecha manualmente, en el caso de que ingrese cualquier tontería se mostrará en rojo y al obtener la fecha la misma sera null, para controlar este comportamiento podemos agregar un patron, una mascara, que le indique al usuario como debe ingresar la fecha si lo quiere hacer de forma manual. Con este codigo:
  JDateChooser dateChooser = new JDateChooser("yyyy/MM/dd", "####/##/##", '_');
 
Indicamos que solo puede ingresar numeros, año/mes/día y en el campo de texto se mostrará este patron "____/__/__" mientras no ingrese o seleccione una fecha.
JDateChooser Máscara
JDateChooser Máscara.
Podemos agregar un JSpinnerDateEditor, para que cuando el usuario ingrese una fecha pueda desplazarse sobre la misma.
  JDateChooser dateChooser = new JDateChooser(null, null, null,
    new JSpinnerDateEditor());
  
JDateChooser JSpinnerDateEditor
JDateChooser JSpinnerDateEditor.
Para obtener la fecha de un JDateChooser.
   dateChooser.getDate();
 
Como hemos visto el JDateChooser no es mas que un campo de texto con un JCalendar que hace de popup al momento de presionar un boton.

5. Ejemplo de JTextFieldDateEditor.


También podemos utilizar solamente el campo de texto JTextFieldDateEditor de esta manera.
private JTextFieldDateEditor textFieldDateEditor;

// Instanciar Componente
textFieldDateEditor = new JTextFieldDateEditor("yyyy/MM/dd",
    "####/##/##", '_');

// Ubicar y agregar al panel
textFieldDateEditor.setBounds...

panel.add(textFieldDateEditor);
 
JTextFieldDateEditor
JTextFieldDateEditor.
Esto puede ser util dependiendo del tipo de aplicación.

Pasando a otros componentes utiles, podemos ver el JDayChooser, JMonthChooser y el JYearChooser.

6. Ejemplo de JDayChooser.


JDayChooser:
private JDayChooser dayChooser;

// Instanciar Componente
dayChooser = new JDayChooser();

// Ubicar y agregar al panel
dayChooser.setBounds...

panel.add(dayChooser);
  
JDayChooser
JDayChooser.

7. Ejemplo de JMonthChooser.


JMonthChooser
private JMonthChooser monthChooser;

// Instanciar Componente
monthChooser = new JMonthChooser();

// Ubicar y agregar al panel
monthChooser.setBounds...

panel.add(monthChooser);
  
JMonthChooser
JMonthChooser.

8. Ejemplo de JYearChooser.


JYearChooser
private JYearChooser yearChooser;

// Instanciar Componente
yearChooser = new JYearChooser();

// Ubicar y agregar al panel
yearChooser.setBounds...

panel.add(yearChooser);
  
JYearChooser
JYearChooser.
Llegando al final de este Tutorial de JCalendar Swing, se puede decir que es una buena librería, muy util en aplicaciones Java Swing. Recuerda que esto fue un repaso, se puede lograr algo mucho mas potente, aquí te dejo el proyecto con los ejemplos para que lo descargues. Suerte.

20 comentarios :

  1. Como puedo mostrar lo seleccionado en un JMonthChooser?

    ResponderEliminar
    Respuestas
    1. Hola Hector, en el caso de que selecciones la fecha desde un JDateChooser y dependiendo de esa fecha quieras mostrar el mes seleccionado en un JMonthChooser podrías hacer algo como esto:

      JMonthChooser monthChooser = new JMonthChooser();

      // Le asignas el mes seleccionado en el JDateChooser
      monthChooser.setMonth(dateChooser.getDate().getMonth());

      Algo parecido puedes hacer con los otros componentes de JCalendar, todos tienen métodos parecidos.

      Suerte!!

      Eliminar
  2. y si necesito buscar una fecha?? como le haria?

    ResponderEliminar
    Respuestas
    1. Hola Ulises Lopez, necesito que te expliques mejor para poder ayudarte! No entiendo a que te refieres exactamente.

      Suerte!!

      Eliminar
  3. ...Excelente explicación, hay otras funciones interesantes que pueden ser manejadas como eventos en un JDateChooser, pero hay un error que aun tiene esta librería:

    https://postimg.org/image/gw6xdhic9/

    Detalle:
    1. Click en jspinner del MonthChooser
    2. Click en jcombobox del Montchooser
    3. Click en cualquier parte fuera del Jcalendar...y salta el error

    ResponderEliminar
    Respuestas
    1. Estimado(a),

      Acabo de descargar el proyecto, hice la prueba desde eclipse y no fui capaz de reproducir esa salida en la consola, siguiendo los pasos de tu imagen te puedo asegurar que no hay ningún error.

      Suerte!!

      Eliminar
  4. Hola como podria saber si el usuario me deja vacia la fecha en un JDateChooser Gracias

    ResponderEliminar
    Respuestas
    1. Estimado, podrías hacer la pregunta de esta manera:
      if(jDateChooser.getDate() != null){
      // no esta vacío
      }

      Saludos!

      Eliminar
  5. tengo dos jdatechooser, como puedo hacer para que seleccoinando un año en el primero, en el segundo jdatechooser tome el mismo año y no se pueda modificar ? me podrias ayudar con eso porfavor te dejo mi codigo

    //desde aqui empieza lo del jdatechooser
    String dia = Integer.toString(jdt.getCalendar().get(Calendar.DAY_OF_MONTH));
    String mes = Integer.toString(jdt.getCalendar().get(Calendar.MONTH)+1);
    String año = Integer.toString(jdt.getCalendar().get(Calendar.YEAR));
    String fecha1 = año + "-" + mes +"-"+dia;

    String dia2 = Integer.toString(jdt2.getCalendar().get(Calendar.DAY_OF_MONTH));
    String mes2 = Integer.toString(jdt2.getCalendar().get(Calendar.MONTH)+1);
    String año2 = Integer.toString(jdt2.getCalendar().get(Calendar.YEAR));
    String fecha2 = año2 + "-" + mes2 +"-"+dia2;

    ResponderEliminar
    Respuestas
    1. Hola Arez Odesska, necesitas agregarle el PropertyChangeListener al JDateChooser y dentro de ese evento hacer tu codigo, un ejemplo de esto (Adaptado a tu codigo) sería algo así:

      jdt.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
      public void propertyChange(java.beans.PropertyChangeEvent evt) {
      // If the 'date' property was changed...
      if ("date".equals(evt.getPropertyName())) {
      try {
      String año = Integer.toString(jdt.getCalendar().get(Calendar.YEAR));

      Calendar cal = Calendar.getInstance();
      cal.set(Integer.parseInt(año), 0, 01);
      // Segundo JDateChooser
      jdt2.setDate(cal.getTime());
      jdt2.setEnabled(false);
      } catch (Exception ex) {
      ex.printStackTrace();
      }
      }
      }
      });

      Esto tiene que funcionarte, Suerte!!

      Eliminar
  6. No sirve la implementacion de la lista, marca error

    ResponderEliminar
    Respuestas
    1. Hola, manda el log del error para ayudarte a ver cual es el problema exacto!

      Eliminar
  7. Buenas Noches datojava he estado interesado en aplicar algunos tips que has puesto con el jCalendar pero en mi caso quisiera deshabilitar dias que ya pasaron y futuros dias (en mi caso que estoy haciendo una agenda).
    tengo un problema al querer aplicarlo
    public static List fechasEspeciales() {
    List fechas = new ArrayList();

    Calendar calendar = new GregorianCalendar(2015, Calendar.SEPTEMBER, 10);
    fechas.add(calendar);
    calendar = new GregorianCalendar(2015, Calendar.NOVEMBER, 10);
    fechas.add(calendar);
    calendar = new GregorianCalendar(2015, Calendar.NOVEMBER, 18);
    fechas.add(calendar);

    return fechas;
    }

    me pide que cree la case calendar lo estoy implementando en un jFrame
    agradeceria tu consejo o ayuda Saludis

    ResponderEliminar
  8. por mas que intento no puedo. no soy de pedir ayuda pero esta vez no pude solucionar hasta hoy el problema.
    Tengo un JDateChooser. Quiero que cuando se cambie al año o el mes se actualice automaticamente la fecha que muestra. Solo se actualiza cuando se hace click en el dia y no en el año o mes. Gracias

    ResponderEliminar
    Respuestas
    1. Hola, la función de JDateChooser es esa, solo actualizara el TextField cuando se seleccione un día, recuerda que también puedes utilizar el JMonthChooser o JYearChooser.

      Suerte!

      Eliminar
  9. Ayuda. Con el JDateChooser no puedo hacer que se actualice su fecha a menos que se haga click en el dia. Quiero que se actualice cuando hago click en el mes o en el año automaticamente por ejemplo selecciono diciembre y hago click en cualquier otra parte menos el boton del dia por ejemplo 10. no se actualiza la fecha del combobox. ¿porque?

    ResponderEliminar
  10. Hola buenas, como podria extraer la fecha seleccionada en un formato valido para introducirla en un base de datos sql?

    Gracias.

    ResponderEliminar
    Respuestas
    1. Hola David Ben, el problema aquí no es ese, con solo obtener la fecha jCal.getDate() obtienes la fecha, ahora la cuestión es, si esa fecha vas a formatearla con un DateFormat y en qué campo quieres agregar dicha fecha, depende del tipo de campo de sql. Si explicas un poco más puedo ayudarte con eso.

      Suerte!!

      Eliminar
  11. Hola Buenas
    Tengo un problema con la implementación de un JCalendar en el que creo que podrías darme alguna orientación.
    Tengo un formulario para mostrar un estadillo de jornadas en el cada trabajador dispone de un JCalendar en el que se muestra si trabaja de mañana, tarde,.... en función de un cambio en el color de fondo del día en cuestión.
    El caso es que si pulsas en cualquiera de los días se muestran en un formulario anejo datos complementarios (hora de entrada, hora de salida, compañeros en la jornada,....) el problema es que al pulsar en ese día el color de fondo de la celda (que como te he dicho define que tipo de jornada es) cambia al que el JCalendar establece por defecto.
    Sería posible evitar este comportamiento?
    Muchas gracias por tu respuesta y un saludo

    ResponderEliminar
    Respuestas
    1. Hola Eu, claro que hay alguna manera de hacerlo, mándame una parte del código, por ejemplo en donde pintas el background. Me parece muy interesante lo que estás haciendo, si quieres compartir parte del proyecto me avisas y podría agregarlo a esta entrada!

      Saludos!

      Eliminar