En este artículo veremos las opciones que nos ofrece la librería SwingUtils para trabajar de forma sencilla con componentes de tipo javax.swing.JComboBox y un modelo de datos genérico.
El API de Java Swing nos ofrece por defecto la clase javax.swing.DefaultComboBoxModel para setearle un Model a nuestros JComboBox, sin embargo, al analizarla a detalle, encontré cosas que no me convencieron de trabajar directamente con dicha clase:
- La primera es que la clase DefaultComboBoxModel guarda los datos en un Vector, lo que hace que los datos estén sincronizados por defecto, y al menos en mi experiencia, son muy pocos los casos en los que vamos a necesitar una colección de datos sincronizada dentro de un JComboBox, además recordemos que la sincronización requiere de más recursos de máquina.
- La segunda, es que podemos encontrarnos casos en los que pasemos una colección de datos la cual por defecto no permita modificaciones, como el caso de Arrays.asList(T ...a) del paquete java.util.Arrays; si nosotros le pasamos por ejemplo la colección Arrays.asList("a", "b", "c").toArray() al constructor de DefaultComboBoxModel(E[] item), éste lo tomará tal cual y no podremos modificar dicho modelo de datos posteriormente, es decir, que si quisiéramos agregar el elemento "d", obtendríamos una excepción.
Por estas razones, decidí agregar la clase ComboBoxModelGeneric a la librería SwingUtils, la cual, a pesar de estar basada en la clase DefaultComboBoxModel, difiere de ésta en lo siguiente:
- La clase ComboBoxModelGeneric guarda los datos en un java.util.List, lo que evita la sincronización por defecto y ahorra recursos de máquina. ¿Y en caso de que necesitemos sincronización? Como mencioné, no es muy frecuente que necesitemos sincronización de datos, sin embargo SwingUtils también soporta el uso de listas sincronizadas en caso de que lo requiramos.
- Por otro lado, los constructores de la clase ComboBoxModelGeneric siempre van a convertir los datos que reciban, en una colección de tipo java.util.ArrayList, lo que garantiza que podamos modificar los datos del modelo de nuestro JComboBox cuando así se requiera.
Ahora si, vamos a ver cómo podemos hacer uso de un modelo de datos para nuestro JComboBox a través de la clase ComboBoxModelGeneric.
==> SwingUtils - Librería de Utilidades para Java Swing
Veamos un sencillo ejemplo de cómo podemos hacer uso de uno de éstos métodos:
Recordemos que un JComboBox nos permite trabajar con tipos de datos genéricos y dicho dato genérico es heredado por su modelo de datos, es decir, que no solamente nos debemos limitar a trabajar con datos de tipo String, sino que podemos tener modelos de datos con otros tipos como enums u objetos creados por nosotros mismos.
Lo único que debemos tener en cuenta es realizar los siguientes ajustes en la clase que usaremos como tipo de dato para nuestro JComboBox:
- Sobrescribir el método toString(), ya que este es el texto que se mostrará en cada ítem del JComboBox en caso de que no pasemos los dos últimos parámetros que explicamos. Si pasamos dichos parámetros, necesitaríamos crear el método que nos retornará el texto que se mostraría en cada ítem.
- Sobrescribir los métodos hashCode() y equals(). En caso de que sean enums, estos métodos no son necesarios; sin embargo, si se trata de una clase creada por nosotros, debemos sobrescribirlos pues son los que se usan para asignar y obtener un valor de un JComboBox.
El API de Java Swing nos ofrece por defecto la clase javax.swing.DefaultComboBoxModel para setearle un Model a nuestros JComboBox, sin embargo, al analizarla a detalle, encontré cosas que no me convencieron de trabajar directamente con dicha clase:
- La primera es que la clase DefaultComboBoxModel guarda los datos en un Vector, lo que hace que los datos estén sincronizados por defecto, y al menos en mi experiencia, son muy pocos los casos en los que vamos a necesitar una colección de datos sincronizada dentro de un JComboBox, además recordemos que la sincronización requiere de más recursos de máquina.
- La segunda, es que podemos encontrarnos casos en los que pasemos una colección de datos la cual por defecto no permita modificaciones, como el caso de Arrays.asList(T ...a) del paquete java.util.Arrays; si nosotros le pasamos por ejemplo la colección Arrays.asList("a", "b", "c").toArray() al constructor de DefaultComboBoxModel(E[] item), éste lo tomará tal cual y no podremos modificar dicho modelo de datos posteriormente, es decir, que si quisiéramos agregar el elemento "d", obtendríamos una excepción.
Por estas razones, decidí agregar la clase ComboBoxModelGeneric a la librería SwingUtils, la cual, a pesar de estar basada en la clase DefaultComboBoxModel, difiere de ésta en lo siguiente:
- La clase ComboBoxModelGeneric guarda los datos en un java.util.List, lo que evita la sincronización por defecto y ahorra recursos de máquina. ¿Y en caso de que necesitemos sincronización? Como mencioné, no es muy frecuente que necesitemos sincronización de datos, sin embargo SwingUtils también soporta el uso de listas sincronizadas en caso de que lo requiramos.
- Por otro lado, los constructores de la clase ComboBoxModelGeneric siempre van a convertir los datos que reciban, en una colección de tipo java.util.ArrayList, lo que garantiza que podamos modificar los datos del modelo de nuestro JComboBox cuando así se requiera.
Ahora si, vamos a ver cómo podemos hacer uso de un modelo de datos para nuestro JComboBox a través de la clase ComboBoxModelGeneric.
Usar un Modelo de Datos Genérico en un JComboBox de Java Swing
Lo primero que debemos hacer es importar la librería SwingUtils a nuestro proyecto. Puedes ver las instrucciones en el siguiente enlace:==> SwingUtils - Librería de Utilidades para Java Swing
Para usar un modelo de la clase ComboBoxModelGeneric, no necesitamos mucho código. Esta clase podemos usarla de forma genérica en cualquier JComboBox, por lo tanto, decidí crear una clase de utilería llamada JComboBoxUtils, mediante la cual es muy fácil asociar nuestro modelo de datos.
Esta clase contiene varios métodos estáticos. Algunos de estos métodos son:
setProperties(final JComboBox<E> jComboBox, List<E> list) setProperties(final JComboBox<E> jComboBox, List<E> list, boolean addElementNullDefault, String textNoSeleccionable) setProperties(final JComboBox<E> jComboBox, List<E> list, boolean addElementNullDefault, String textNoSeleccionable, boolean isSynchronized, boolean needDetectConcurrentModifications, Class clazz, String nameMethod)
El primer método es la configuración rápida por defecto. Con éste método, tan sólo debemos pasar nuestro JComboBox, el cual ya debe estar inicializado previamente, y la lista de datos que deseamos agregar a nuestro modelo. Éste método además de crear el modelo de datos usando la clase ComboBoxModelGeneric y asociárselo al JComboBox, crea un elemento null con la leyenda "- Seleccione -" al principio de la lista de datos.
El segundo método funciona de forma similar al segundo; sin embargo, a éste podemos indicarle si queremos que agregue el elemento null por defecto al principio de la lista de datos o no, y la leyenda que quisiéramos que tuviera este elemento en caso de que indiquemos true al parámetro addElementNullDefault.
El tercer método, correspondería a la configuración completa, y además de las configuraciones mencionadas en los dos métodos anteriores, podemos indicarle si queremos que sea una lista de datos sincronizada o no, además de poderle indicar si queremos que nuestra lista detecte modificaciones concurrentes. Para entender en qué afecta este atributo a la lista de datos, puedes revisar el siguiente artículo: Diferencias entre ArrayList sincronizado y CopyOnWriteArrayList en Java. Este cambio sólo tendrá efecto si se pasa el parámetro isSynchronized en true. Los dos últimos parámetros corresponden a cómo queremos que se muestren los datos; veamos cómo los usaríamos.
Lo que se muestra en los ítems de un JComboBox por defecto son String, así que si le pasamos una lista de objetos creados por nosotros, por defecto se mostrará lo que esté en el método toString(). ¿Pero qué pasa si nuestro método toString() ya está siendo usado para otra cosa? No se, supongamos que para alguna característica de nuestra aplicación se está devolviendo un código o algo así, pero en nuestro JComboBox lo que deseamos es mostrar una descripción, ¿Qué hacemos en dicho caso?
Para eso son estos dos últimos parámetros. El primero es el class de nuestro objeto, que dicho sea de paso, debe ser del mismo tipo que la lista de datos que estamos pasando al JComboBox, y el segundo es el nombre del método que retornará el valor a mostrar en cada ítem; dicho método debe retornar un valor de tipo String y debe estar declarado en la clase que pasamos en el primer parámetro.
El tercer método, correspondería a la configuración completa, y además de las configuraciones mencionadas en los dos métodos anteriores, podemos indicarle si queremos que sea una lista de datos sincronizada o no, además de poderle indicar si queremos que nuestra lista detecte modificaciones concurrentes. Para entender en qué afecta este atributo a la lista de datos, puedes revisar el siguiente artículo: Diferencias entre ArrayList sincronizado y CopyOnWriteArrayList en Java. Este cambio sólo tendrá efecto si se pasa el parámetro isSynchronized en true. Los dos últimos parámetros corresponden a cómo queremos que se muestren los datos; veamos cómo los usaríamos.
Lo que se muestra en los ítems de un JComboBox por defecto son String, así que si le pasamos una lista de objetos creados por nosotros, por defecto se mostrará lo que esté en el método toString(). ¿Pero qué pasa si nuestro método toString() ya está siendo usado para otra cosa? No se, supongamos que para alguna característica de nuestra aplicación se está devolviendo un código o algo así, pero en nuestro JComboBox lo que deseamos es mostrar una descripción, ¿Qué hacemos en dicho caso?
Para eso son estos dos últimos parámetros. El primero es el class de nuestro objeto, que dicho sea de paso, debe ser del mismo tipo que la lista de datos que estamos pasando al JComboBox, y el segundo es el nombre del método que retornará el valor a mostrar en cada ítem; dicho método debe retornar un valor de tipo String y debe estar declarado en la clase que pasamos en el primer parámetro.
Veamos un sencillo ejemplo de cómo podemos hacer uso de uno de éstos métodos:
List<String> lista = Arrays.asList("Amarillo", "Azul", "Rojo", "Verde", "Gris", "Negro", "Blanco"); JComboBoxUtils.setProperties(miJComboBox, lista);
Recordemos que un JComboBox nos permite trabajar con tipos de datos genéricos y dicho dato genérico es heredado por su modelo de datos, es decir, que no solamente nos debemos limitar a trabajar con datos de tipo String, sino que podemos tener modelos de datos con otros tipos como enums u objetos creados por nosotros mismos.
Lo único que debemos tener en cuenta es realizar los siguientes ajustes en la clase que usaremos como tipo de dato para nuestro JComboBox:
- Sobrescribir el método toString(), ya que este es el texto que se mostrará en cada ítem del JComboBox en caso de que no pasemos los dos últimos parámetros que explicamos. Si pasamos dichos parámetros, necesitaríamos crear el método que nos retornará el texto que se mostraría en cada ítem.
- Sobrescribir los métodos hashCode() y equals(). En caso de que sean enums, estos métodos no son necesarios; sin embargo, si se trata de una clase creada por nosotros, debemos sobrescribirlos pues son los que se usan para asignar y obtener un valor de un JComboBox.
Como podemos apreciar, es muy sencillo asociar un modelo de datos genérico a cualquier JComboBox de Java Swing que tengamos usando la librería SwingUtils.
No hay comentarios.:
Publicar un comentario