lunes, noviembre 20, 2006

Tablas en java I –Jtables, Modelos,TableModel, JScrollPane

Las tablas en java son otros de los componentes difíciles de crear para los usuarios inexpertos. Quizás por sus grandes capacidades y posibilidades de utilización, es que no se crean con un simple arrastrar y soltar con nuestro ide favorito, o por lo menos no como nosotros queremos.
Importando javax.swing.JTable ya estaremos en condiciones de empezar a crear tablas. Pero a los fines de explicar la forma más sencillas de crearlas, no comenzaremos por ahí. Ya que, a mi entender, lo mas fácil es crear un modelo de tabla que luego utilizaremos. Luego crearemos la tabla, y finalmente crearemos el JScrollPane que la contendrá, para hacer la tabla escrolable.

Creando un Modelo de Tabla –TableModel

El modelo de tabla será aquel que determine la forma que nuestra tabla tendrá, y su comportamiento ante los eventos.
Generalmente utilizamos un tabla para listar algo, o cargar datos de forma rapida, por ejemplo personas. En este ejemplo utilizare una clase Personas que tiene tres atributos: Apellido, Nombre (Strings) y número de documento (int).
Lo primero que hay que hacer es crear una clase que implemente la interfaz TableModel. En dicha clase se instanciaran tres variables; dos del tipo LinkedList y una del tipo Persona.

public class MyModelo implements TableModel{
private LinkedList datos = new LinkedList();
private LinkedList listeners = new LinkedList();

Peronas persona =new Peronas();

….
}

La clase LinkedList es una especie de lista que permite incluir y manejar elementos a través de operaciones. Pudiendo ser de cualquier tipo, incluso null. Esta clase nos brinda métodos uniformados para insertar, borrar, obtener y poner elementos en la lista.
La implementación de la interfaz TableModel nos obliga a la utilización de algunos métodos que mostrare a continuación:

1)
public int getColumnCount() {
return 3;
}

Este metodo determina la cantidad de columnas que la tabla tendera. Por ejemplo si queremos que la tabla tenga 3 debemos retornar el numero 3

2)
public int getRowCount() {
return datos.size();
}

Retorna la cantidad de filas, se basa en la lista de elementos declarada con anterioridad.

3) Hora viene uno de los métodos mas importantes el que servirá para obtener los datos de la lista.

public Object getValueAt(int rowIndex, int columnIndex) {
Personas aux;
//castemos el dato de la lista a una variable del tipo Personas
aux = (Personas)(datos.get(rowIndex));
// Se obtendra la persona seleccionada según el numero de fila
switch (columnIndex)
{
case 0:
return aux.getDni();
case 1:
return aux.getApellido();
case 2:
return aux.getNombre();
default:
return null;
}
}

4) asi como tenemos el metodo get existe el metodo set

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
Personas aux;
aux = (Personas)(datos.get(rowIndex));
switch(columnIndex)
{
case 0:
aux.setDni((Integer)aValue);
break;
case 1:
aux.setApellido((String)aValue);
break;
case 2:
aux.serNombre((String)aValue);
break;
default:
break;
}

TableModelEvent evento = new TableModelEvent (this, rowIndex, rowIndex,
columnIndex);
avisaSuscriptores (evento);
}

aValue es un objeto que se pasa como parametro y que contendrá, en nuestro caso, a la persona, pero para convertirla primero debemos castearlo.
Un TableModelEvent se utilizar para notificar a los suscriptores (todos aquellos que necesitan conocer las actividades que se realizan sobre el modelo, por ejemplo la tabla) que el tablemodel a cambiado.

5)
public Class getColumnClass(int columnIndex) {
// Devuelve la clase que hay en cada columna.
switch (columnIndex){
case 0:
return Integer.class;
case 1:
return String.class;
case 2:
return String.class;
default:
return Object.class;
}
}

Nos permitirá obtener las clases de cada columna para utilizarla después.

6)
public String getColumnName(int columnIndex) {
switch (columnIndex)
{
case 0:
return "DNI";
case 1:
return "Apellido";
case 2:
return “Nombre”;
default:
return null;
}
}
Este metodo permite definir el nombre de los campos que saldran en el encabezado de la tabla.

7)
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}

Determina si la celda es editable, nosotros podemos jugar con condicionales para determinar que columnas serán editables y cuales no. En este caso todas las celdas son editables.

8)
public void addTableModelListener(TableModelListener l) {
// Añade el suscriptor a la lista de suscriptores
listeners.add (l);
}

9)
public void removeTableModelListener(TableModelListener l) {
// borra un suscriptor
listeners.remove(l);
}

Una ves que terminamos con todos lo métodos que se nos exige implementar, podemos empezar a crear nuestros propios métodos para el manejo de los datos de las celdas.
Lo primero que aremos será crear el método que avise a los suscriptores que el modelo a cambiado y por lo tanto la tabla deberá cambiar.

private void avisaSuscriptores (TableModelEvent evento){
int i;
for (i=0; i
((TableModelListener)listeners.get(i)).tableChanged(evento);
}

Después comenzaremos a crear los metodos para insertar, borrar y acualizar las personas de la tabla

Insertar

public void insertarPersona (Personas nuevaPersona){
// Añade la persona al modelo
datos.add (nuevaPersona);
// Avisa a los suscriptores creando un TableModelEvent...
TableModelEvent evento;
evento = new TableModelEvent (this, this.getRowCount()-1,
this.getRowCount()-1, TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT);
// ... y avisando a los suscriptores
avisaSuscriptores (evento);
}

Con el metodo LinkedList.add() agregamos un elemento a la lista de elemntos que contiene los datos de las personas. Después de ello debemos crear un TableModelEvent que permita notificar de la inserción del dato a la lista.

La estructura del constructor del TableModelEvent que utilizamos es:

TableModelEvent(TableModel modeloDeTabla, int filaInicio, int filaFin, int columna, int tipoEvento)

En este caso en particular, estamos incertando en la ultima fila por que la fila de inicio y de fin es la misma , los cambios se realizarán en todas las columnas, y el evento es un INSERT.

Borrar

public void borrarPerona (int fila){
datos.remove(fila);
TableModelEvent evento = new TableModelEvent (this, fila, fila,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE);

avisaSuscriptores (evento);
}

Similar a al anterior pero para borrar.

Actualizar

public void updateTurno(Turnos turno_completo, int fila){
datos.remove(fila);
datos.add(fila,turno_completo);
TableModelEvent e =new TableModelEvent(this,fila,fila,TableModelEvent.ALL_COLUMNS,TableModelEvent.UPDATE);
this.avisaSuscriptores(e);
}

A la hora de realizar el update, prefiero primero remover de la lista el elemento (persona) que se encuentra en el lugar indicado por el parametro fila, para despues realizar la acutalizacion.

Construyendo la tabla

Una vez creado el modelo de tabla que vamos a utilizar, solo resta crear la tabla.
Después de ver distintos códigos de cómo se crearon tablas y scrollpane, y luego se le asignaban restricciones, layouts y metodos etc, etc, encontré navegando la forma mas sencilla de crearla:
En el frame que vamos a utilizar, podemos arrastrar y soltar algún JScrollPane así lo ubicamos y le damos el tamaño que deseamos. Luego vamos al codigo y escrivimos:

MyModelo modelo =new MyModelo();
JTable tabla =new JTable(modelo);
JScrollPane jScrollPane1 =new JScrollPane(tabla);//este es el scroll creado por el ide y
//le modificamos el constructor pasandole como parametro la tabla

Sencillito no? y así, como por arte de magia tendremos una tabla. Eso si después si queremos, podemos agregar código para darle a nuestra tabla un comportamiento mas profesional.

Trabajando con los datos de la tabla

Si queremos cargar un dato de la tabla a una variable para que la podamos manejar directamente de la memoria podemos hacer uso del los eventos del Mouse o de algún botón. Se puede realizar código que cargue todos los datos o seleccionar uno… en fin las posibilidades son muchas.

En el caso de insertar la persona hacemos:

Personas p = new Personas(25425456,”Lopez”,”Juan”);
modelo.insertarPersona(p);

..y la persona se agregara al final de la tabla.
De forma similar trabajamos con el resto de los métodos del modelo.
Mas adelante, escribiré como definir el tamaño de las columnas, y las posibilidades de agregarle componentes a las celdas, imágenes, colores, etc.
Espero haber sido de ayuda, saludos y hasta la proxima.

6 comentarios:

Anónimo dijo...

Hola, es la primera vez que entro... Incluso fue por pura suerte el que entrara aquí. Pero por Dios!! No sabes cuánto me ayudó esta super-detallada explicación sobre la creación de JTableModel... De verdad, muchas gracias!

Atte. Un usuario -estudiante- agradecido :P

aro dijo...

De nada tmaxtor, esa es la idea, darnos una mano entre todos.
Saludos

MCKAY Brothers dijo...

primero: sugiero que pongas el ingreso de comentarios en la misma ventana ya que mi navegador asi como el opera no soporta dichopopup (tuve que ir a un cyber)

ok, esta muy interesante y espero puedas ayudarme en algo:

en el siguiente codigo capturo dos refcursor de postgres, esto no es nada del otro mundo:

PrepareStatement statementDataP = connection.prepareStatement( "FETCH ALL IN \""+ cursorArray.get(1) + "\";" , ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
statementDataP.setMaxRows(500);
ResultSet datatable = statementDataP.executeQuery();

..

el detalle es que si me devuelve un fecth de mas de 100 registros se me acaba la memoria que de por si el manejo y tamaño de la misma ya la he puesto agresiva y ademas la JVM tiene asignado en los parametros -Xms128m -Xmx512m

como puedo capturar tanto tamaño de data en un resultset, algo asi como unos 1000000 rows me vienen...

MCKAY Brothers dijo...

ah! se que no es swing pero creo si puedes con swint y Jtable que es horrendo (pefiero javax) podrias sugerir algo, es que no he visto nada en la red..

Anónimo dijo...

Hola con todas estoy realizando una palicacion independiente con el ejemplo y los datos los capturo por medio de cajas de texto pero la verdad no me funciona por fa me pueden ayudad

aro dijo...

chicos, perdon por la ausencia en contestar, la verdad es que estos post fueron escritos hace mucho tiempooo, je. Y como que se le termino el soporte jeje. Vi que hay muchas busquedas de esto, asi que voy a tratar de escribir nuevos post de esto. Pero el codigo de los ejemplos siempre es compilado y testeado, asi que por ahi debe haber alguna cosa que se me olvido de publicar. Pero no creo que la valla a buscar... por que ni idea donde puede estar...tal vez en algun basural junto con mis viejas compus je.