JTable: Ordenar y filtrar filas

De ChuWiki
Saltar a: navegación, buscar

Desde java 6 tenemos las clases TableRowSorter y RowFilter que nos permiten ordenar y filtrar las filas de un JTable de java. Vamos aquí a ver un ejemplo sencillo de cómo se usa.


TableRowSorter: el que permite ordenar el JTable

Para que la tabla sea ordenable no necesitamos hacer grandes cosas. Basta con pasarle al JTable una instancia de TableRowSorter. A partir de ese momento, haciendo click en la cabecera de las columnas con el ratón, ordenaremos el JTable en orden ascendente o descendente alternativamente según esa columna.

// Instanciamos nuestro modelo de datos, por ejemplo, DefaultTableModel
// y lo metemos en el JTable
DefaultTableModel modelo = new DefaultTableModel();
JTable tabla = new JTable(modelo);

// Instanciamos el TableRowSorter y lo añadimos al JTable
TableRowSorter<TableModel> elQueOrdena = new TableRowSorter<TableModel>(modelo);
tabla.setRowSorter(elQueOrdena);

Listo, no necesitamos hacer más.


RowFilter: el que permite filtrar el JTable

Para el filtro, sólo tenemos que pasarle a nuestro TableRowSorter un RowFilter una columna concreta, por medio del método setRowFilter(). Este RowFilter es el que dice si un valor de esa columna (y por tanto la fila entera del JTable) pasa o no pasa el filtro. Si el valor de esa columna no pasa el filtro, la fila entera no lo pasa y no será visible.

Podemos hacernos nuestros propios RowFilter heredando de esta clase e implementando su método abstracto include(), pero RowFilter tiene varios métodos estáticos que nos proporcionan los filtros habituales.

En nuestro ejemplo, usaremos un filtro regex, es decir, el dato pasa el filtro si cumple un determinado patrón, que será muy simple: pasa el filtro si tiene un "2". Para obtener dicho RowFilter, usamos el método RowFilter.regexFilter().

Como primer parámetro se pasa una expresión regular (regex) que tiene que cumplir el dato para pasar el filtro. En nuestro caso es un simple String con un "2" dentro.

Como segundo parámetro se pasa un entero para identificar la columna a la que se quiere aplicar el filtro. La primera columna es el cero. En nuestro caso, lo haremos sobre la segunda columna, así que pasaremos un 1.

modeloOrdenado.setRowFilter(RowFilter.regexFilter("2", 1));

Y ya está. Esto hará que se oculten todas las filas cuya segunda columna no tenga un 2.

El código completo del ejemplo

Aquí un ejemplo con el código completo.

package chuidiang.ejemplos.jtable;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

/**
 * Ejemplo de uso de TableRowSorter y RowFilter.
 * 
 * @author Chuidiang
 * 
 */
public class PruebaJTable {

	private TableRowSorter<TableModel> modeloOrdenado;

	/**
	 * main del ejemplo.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new PruebaJTable();
	}

	/**
	 * Instancia un JFrame con un JTable dentro y diez filas de datos. Lleva un
	 * trozo de código comentado para poder reemplazar.
	 */
	public PruebaJTable() {
		JFrame v = new JFrame("Prueba JTable");

		// Modelo de datos, segunda columna Integer y primera String. Los
		// índices empiezan en cero.
		DefaultTableModel modelo = new DefaultTableModel() {
			@Override
			public Class getColumnClass(int columna) {
				if (columna == 1)
					return Integer.class;
				return String.class;
			}
		};

		// Añadimos unos datos.
		modelo.addColumn("columna 1");
		modelo.addColumn("columna 2");
		for (int i = 0; i < 10; i++) {
			modelo.addRow(new Object[] { "" + i, 100 - i });
		}

		// Metemos el modelo ordenable en la tabla.
		modeloOrdenado = new TableRowSorter<TableModel>(modelo);
		tabla.setRowSorter(modeloOrdenado);
		modeloOrdenado.setRowFilter(RowFilter.regexFilter("2", 1));

		// Lo pintamos todo en la ventana y la mostramos.
		JTable tabla = new JTable(modelo);
		JScrollPane scroll = new JScrollPane(tabla);
		v.getContentPane().add(scroll);
		v.pack();
		v.setVisible(true);
		v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

	}
}

Otros filtros ya construidos

RowFilter tiene además los siguientes métodos:


RowFilter.regexFilter()

El que hemos visto en el ejemplo. El siguiente filtro hace que pasen las filas que en la primera columna tengan un texto que empiece por "a" minúscula

RowFilter.regexFilter("^a", 0);


RowFilter.dateFilter()

Para fechas. El siguiente filtro haría que pasaran el filtro aquellas fechas anteriores a la actual en la columna 2.

RowFilter.dateFilter(ComparisonType.BEFORE, new Date(),1);


RowFilter.numberFilter()

Para números. El siguiente filtro haría que pasaran el filtro las filas con un 10 en la primera columna

RowFilter.numberFilter(ComparisionType.EQUAL, 10, 0);


RowFilter and, or y not

Si hemos construido ya varios RowFilter cualesquiera y los tenemos metidos en un Iterable, podemos hacer operaciones lógicas and, or y not con ellos

LinkedList<RowFilter> lista = new LinkedList<RowFilter>();
lista.add(RowFilter.dateFilter(....));
lista.add(RowFilter.regexFilter(....));

RowFilter filtroAnd = RowFilter.andFilter(lista); // and de ambos filtros
RowFilter filtroOr = RowFilter.orFilter(lista);  // or de ambos filtros.
RowFilter filtroNo = RowFilter.notFilter(lista.getFirst());