JTable

De ChuWiki

JTable y DefaultTableModel[editar]

La forma más sencilla de usar un JTable y tener toda su funcionalidad es instanciar un DefaultTableModel y meterlo en el JTable, en el constructor

DefaultTableModel modelo = new DefaultTableModel();
JTable tabla = new JTable(modelo);

Aunque en realidad esto no es estrictamente necesario, porque un JTable por defecto ya tiene dentro un DefaultTableModel, así que también sería válido esto otro

JTable tabla = new JTable();
DefaultTableModel modelo = (DefaultTableModel)tabla.getModel();

Una vez que tenemos el modelo, de una u otra forma, podemos añadir columnas directamente en el modelo

modelo.addColumn("etiqueta columna 1");
modelo.addColumn("etiqueta columna 2");

Podemos añadir datos directamente en el modelo, así como borrarlos o modificarlos

Object [] fila = new Object[2];
fila[0] = "dato columna 1";
fila[1] = "dato columna 3";
modelo.addRow ( fila ); // Añade una fila al final
modelo.setValueAt ("nuevo valor", 0, 1); // Cambia el valor de la fila 1, columna 2.
modelo.removeRow (0); // Borra la primera fila

Todo lo que hagamos se reflejará de inmediato en el JTable.

Obtener fila y columna del JTable en la que se hace click[editar]

A veces nos interesa seleccionar una fila del JTable para hacer algo con ella (sacar un menú, recoger datos para mostrarlos en otro sitio, etc).

Una forma de hacerlo es añadiendo un MouseListener al JTable, de esta manera

tabla.addMouseListener(new MouseAdapter() 
   {
      public void mouseClicked(MouseEvent e) 
      {
         int fila = tabla.rowAtPoint(e.getPoint());
         int columna = tabla.columnAtPoint(e.getPoint());
         if ((fila > -1) && (columna > -1))
            System.out.println(modelo.getValueAt(fila,columna));
      }
   });

Hemos añadido un MouseAdapter para no tener que implementar todos los métodos del MouseListener.

Con el método tabla.rowAtPoint() es posible enterarnos en qué fila de del JTable ha ocurrido el evento del ratón (el click en este caso). Para ello basta llamar a este método pasándole las coordenadas x,y del evento de ratón, que se obtienen con el método e.getPoint().

Una vez que sabemos la fila, debemos comprobar si es mayor que -1. El método rowAtPoint() nos devuelve -1 si pinchamos en el JTable, pero fuera de cualquier fila. Es el caso de que el JTable tenga un tamaño en pixels superior al que le corresponde según su número de filas.

Lo mismo vale para columnAtPoint().

Una vez que tenemos la fila y sabemos que no es -1, es fácil a través del modelo obtener los datos correspondientes. En este caso se escribe por pantalla con un System.out.prinln() el valor de la fila y columna que se ha seleccionado.

Hacer que una celda del JTable no sea editable[editar]

Si usamos DefaultTableModel las celdas del JTable son editables por defecto. A veces esto no nos interesa y JTable no tiene métodos para impedirlo. La forma de decidir qué celdas son o no editables es hacer nuestro propio modelo de datos, nuestro TableModel. La forma sencilla de hacerlo es heredar de DefaultTableModel y redefinir el método isCellEditable() para que sirva a nuestros propositos

public class MiModelo extends DefaultTableModel
{
   public boolean isCellEditable (int row, int column)
   {
       // Aquí devolvemos true o false según queramos que una celda
       // identificada por fila,columna (row,column), sea o no editable
       if (column == 3)
          return true;
       return false;
   }
}

En este ejemplo, hemos creado nuestro propio modelo de datos que hace que la columna 4 (los índices empiezan en cero) de la tabla sea editable y el resto no. Ahora simplemente instanciamos el JTable usando este modelo y rellenamos los datos igual que antes

MiModelo modelo = new MiModelo();
JTable tabla = new JTable(modelo);


Cambiar el tipo de dato con DefaultTableModel[editar]

DefaultTableModel por defecto le dice al JTable que todos los datos que tiene son Object. A veces, porque queramos cambiar el TableCellRenderer o cualquier otro motivo, nos interesa que determinadas columnas se consideren como Boolean, como Integer o cualquier otro tipo de dato.

Para modificar esto, tenemos que crearnos nuestro propio modelo de Datos. La forma más sencilla es heredar de DefaultTableModel y redefinir el método getColumnClass().

public class MiModelo extends DefaultTableModel
{
   /** Primera columna Boolean, segunda Integer y el resto Object */
   public Class getColumnClass(int columna)
   {
      if (columna == 0) return Boolean.class;
      if (columna == 1) return Integer.class;
      return Object.class;
   }
}

En el ejemplo se ha hecho que la primera columna sea de Boolean, la segunda de Integer y el resto de Object.

Una cosa curiosa de los Boolean, es que el JTable al pintarlos los pone como JCheckBox.

Hacer visible una fila concreta del JTable dentro de un JScrollPane[editar]

Para que un JTable tenga barras de scroll y tenga una "cabecera" con las etiquetas de las columnas, es necesario meterla en un JScrollPane. Esto se puede hacer de dos formas.

JTable tabla = new JTable();
JScrollPane scroll = new JScrollPane(tabla);

o bien

JTable tabla = new JTable();
JScrollPane scroll = new JScrollPane();
scroll.setViewportView(tabla);

es bastante habitual al principio equivocarse y usar el método add(), que NO funcionará correctamente

JTable tabla = new JTable();
JScrollPane scroll = new JScrollPane();

// Esto NO funciona.
scroll.add(tabla);

Cuando tenemos un JTable metido dentro de un JScrollPane, a veces queremos que las barras de scroll se desplacen para que una determinada celda sea visible.

No conozco una forma inmediata de hacerlo, pero una posible solución es esta.

...
// Nos devuelve la posición en pixels de una celda en fila,columna
Rectangle r = tabla.getCellRect( fila, columna, true);

// Mueve el scroll para que el rectangulo sea visible
scrollPane.getViewport().scrollRectToVisible (r);


Enlaces[editar]