En algunos foros he visto que constantemente la gente pregunta como pueden filtrar los resultados de una consulta mostrada en un JTable al escribir en un JTextField. Esto es algo muy útil en aplicaciones donde se desee realizar una búsqueda de cualquier cosa; por ejemplo en una aplicación de punto de venta donde se desee buscar algún producto, en una librerÃa para buscar algún libro, en una aplicación para el registro de notas académicas donde se deseen buscar datos de estudiantes, etc.
Antes de empezar este tutorial, primero se deben tener en cuenta algunas consideraciones:
- Este proceso se realiza de igual forma para datos estáticos en un JTable, o para resultados que son producto de una consulta a una base de datos.
- Para realizar el filtrado de los resultados, los datos deben estar de antemano en la Tabla, es decir, ya debe estar creado el modelo del JTable. Además si no se hiciera asÃ, imagina que pasarÃa si se hiciera por ejemplo una consulta a una tabla de una base de datos que tiene un millón de registros; cada vez que digitemos una letra, habrÃa que hacer la consulta a todo el millón de registros, lo cual en cualquier momento saturará el servidor de la base de datos.
En este caso, haremos una tabla que llenaremos nosotros mismos con algunos datos de personas como su identificación, nombre y profesión, pero como lo dije anteriormente, funciona de igual manera para datos recogidos desde una consulta a una base de datos (La consulta debe hacerse primero, por ejemplo podrÃa hacerse en el constructor de la clase).
¿Qué Usaremos Para Este Tutorial?
- NetBeans v7.4
- Java 1.7
Nivel: Intermedio
Tiempo: 20 minutos
1. Creamos un proyecto en NetBeans con la siguiente estructura:
2. Creamos la interfaz de usuario la cual comprende un JFrame donde hemos agregado 3 JRadioButtons con su respectivo ButtonGroup, un JLabel, un JTextField y un JTable.
3. Creamos el modelo del JTable y sus respectivos datos. Para esto crearemos un método para el modelo y otro para llenar la tabla con datos:
private DefaultTableModel tabladatos; public final void setModeloTabla() { // Inicializamos el modelo de la tabla tabladatos = new DefaultTableModel(); // Creamos los tÃtulos de la tabla y los insertamos en el modelo String[] titulostabla = {"Identificación","Nombre","Profesión"}; tabladatos.setColumnIdentifiers(titulostabla); // Insertamos el modelo creado en el JTable this.jTdatos.setModel(tabladatos); } public void cargarDatos() { // Creamos una matriz con los datos que llenarán la tabla Object[][] datos = { {98735671,"Felipe Gomez","Arquitecto"}, {56319046,"Sandra Rios","Docente"}, {11653215,"Camilo Rodriguez","Ingeniero"}, {83211674,"Maria Lopez","Oficial de Policia"}, {76325901,"David Ospina","Docente"}, {90119740,"Hector Cortes","Ingeniero"}, {65267938,"Laura Martinez","Docente"}, {10941507,"El Javatar","Ingeniero"}, {30297534,"Camila Salas","Oficial de Policia"}, {28016745,"Pedro Fernandez","Arquitecto"}, }; // Recorremos las filas de la matriz para ir llenando la tabla for (Object[] dato : datos) { tabladatos.addRow(dato); } }
4. Añadimos éstos dos métodos al constructor de la clase:
De esta forma si quisieramos llenar la tabla con datos provenientes de una consulta a una base de datos, solo cambiarÃamos el código que va dentro del método cargarDatos().
Si ejecutáramos nuestro proyecto en éste momento, se verÃa de la siguiente forma:
Ahora solo nos resta crear el método encargado de realizar el filtro y adjuntarlo a un evento del JTextField, pero vamos por partes.
5. Creamos el método encargado de realizar el filtro:
6. Ahora lo que haremos es añadirle un evento de tipo KeyTyped al JTextField, el cual a su vez tendrá un KeyListener que a su vez estará escuchando las acciones emitidas dentro de otro evento KeyTyped. Éste último evento será el que llamará al método filtro():
El código completo (omitiendo algunas partes del código generado por NetBeans) quedarÃa de la siguiente forma:
Ejecutamos el proyecto y listo. Próximamente estaré publicando el video donde muestro paso a paso la realización de este proyecto.
public Interfaz() { initComponents(); setModeloTabla(); cargarDatos(); }
De esta forma si quisieramos llenar la tabla con datos provenientes de una consulta a una base de datos, solo cambiarÃamos el código que va dentro del método cargarDatos().
Si ejecutáramos nuestro proyecto en éste momento, se verÃa de la siguiente forma:
5. Creamos el método encargado de realizar el filtro:
public void filtro() { //Obtenemos el valor del JTextField para el filtro String filtro = jTFfiltrar.getText(); // Identificamos cual es el JRadioButton seleccionado para filtrar el // resultado de acuerdo a los datos de la columna elegida if (jRBident.isSelected()) { int columna = 0; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } else if (jRBnombre.isSelected()) { int columna = 1; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } else if (jRBprofesion.isSelected()) { int columna = 2; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } }
6. Ahora lo que haremos es añadirle un evento de tipo KeyTyped al JTextField, el cual a su vez tendrá un KeyListener que a su vez estará escuchando las acciones emitidas dentro de otro evento KeyTyped. Éste último evento será el que llamará al método filtro():
private void jTFfiltrarKeyTyped(java.awt.event.KeyEvent evt) { // Comprobamos que el ButtonGroup que nosotros llamamos bGfiltar tenga // seleccionado alguno de los tres JRadioButtons que le hemos agregado if (bGfiltrar.getSelection()==null) { // Si ninguno de los JRadioButtons está seleccionado, evitamos que se // escriba algo dentro del JTextField y mostramos un mensaje de error evt.consume(); JOptionPane.showMessageDialog(this, "Debe seleccionar una opción del filtro", "Menaje de Error", JOptionPane.ERROR_MESSAGE); } else { // Añadimos al JTextField un KeyListener con un KeyAdapter. De esta // forma es como si dieramos enter cada vez que digitamos una techa jTFfiltrar.addKeyListener(new KeyAdapter() { @Override public void keyTyped(final KeyEvent e) { // Llamamos al método encargado de realizar el filtro filtro(); } }); // Inicializamos el objeto trsfiltro de la clase TableRowSorter con // el modelo de la tabla, que para nuestro caso es tabladatos trsfiltro = new TableRowSorter(tabladatos); // Añadimos al Jtable el filtro trsfiltro jTdatos.setRowSorter(trsfiltro); } }
El código completo (omitiendo algunas partes del código generado por NetBeans) quedarÃa de la siguiente forma:
package filtrarjtable; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JOptionPane; import javax.swing.RowFilter; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableRowSorter; /** * * @author Andres */ public class Interfaz extends javax.swing.JFrame { private DefaultTableModel tabladatos; private TableRowSorter trsfiltro; /** * Creates new form Interfaz */ public Interfaz() { initComponents(); setModeloTabla(); cargarDatos(); } public final void setModeloTabla() { // Inicializamos el modelo de la tabla tabladatos = new DefaultTableModel(); // Creamos los tÃtulos de la tabla y los insertamos en el modelo String[] titulostabla = {"Identificación","Nombre","Profesión"}; tabladatos.setColumnIdentifiers(titulostabla); // Insertamos el modelo creado en el JTable this.jTdatos.setModel(tabladatos); } public void cargarDatos() { // Creamos una matriz con los datos que llenarán la tabla Object[][] datos = { {98735671,"Felipe Gomez","Arquitecto"}, {56319046,"Sandra Rios","Docente"}, {11653215,"Camilo Rodriguez","Ingeniero"}, {83211674,"Maria Lopez","Oficial de Policia"}, {76325901,"David Ospina","Docente"}, {90119740,"Hector Cortes","Ingeniero"}, {65267938,"Laura Martinez","Docente"}, {10941507,"El Javatar","Ingeniero"}, {30297534,"Camila Salas","Oficial de Policia"}, {28016745,"Pedro Fernandez","Arquitecto"}, }; // Recorremos las filas de la matriz para ir llenando la tabla for (Object[] dato : datos) { tabladatos.addRow(dato); } } public void filtro() { //Obtenemos el valor del JTextField para el filtro String filtro = jTFfiltrar.getText(); // Comprobamos if (jRBident.isSelected()) { int columna = 0; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } else if (jRBnombre.isSelected()) { int columna = 1; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } else if (jRBprofesion.isSelected()) { int columna = 2; trsfiltro.setRowFilter(RowFilter.regexFilter(filtro, columna)); } } private void initComponents() { // ... Código generado por NetBeans } private void jTFfiltrarKeyTyped(java.awt.event.KeyEvent evt) { // Comprobamos que el ButtonGroup que nosotros llamamos bGfiltar tenga // seleccionado alguno de los tres JRadioButtons que le hemos agregado if (bGfiltrar.getSelection()==null) { // Si ninguno de los JRadioButtons está seleccionado, evitamos que se // escriba algo dentro del JTextField y mostramos un mensaje de error evt.consume(); JOptionPane.showMessageDialog(this, "Debe seleccionar una opción del filtro", "Menaje de Error", JOptionPane.ERROR_MESSAGE); } else { // Añadimos al JTextField un KeyListener con un KeyAdapter. De esta // forma es como si dieramos enter cada vez que digitamos una techa jTFfiltrar.addKeyListener(new KeyAdapter() { @Override public void keyTyped(final KeyEvent e) { // Llamamos al método encargado de realizar el filtro filtro(); } }); // Inicializamos el objeto trsfiltro de la clase TableRowSorter con // el modelo de la tabla, que para nuestro caso es tabladatos trsfiltro = new TableRowSorter(tabladatos); // Añadimos al Jtable el filtro trsfiltro jTdatos.setRowSorter(trsfiltro); } } /** * @param args the command line arguments */ public static void main(String args[]) { // ... Código generado por NetBeans } // Variables declaration - do not modify private javax.swing.ButtonGroup bGfiltrar; private javax.swing.JLabel jLabel1; private javax.swing.JRadioButton jRBident; private javax.swing.JRadioButton jRBnombre; private javax.swing.JRadioButton jRBprofesion; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextField jTFfiltrar; private javax.swing.JTable jTdatos; // End of variables declaration }
Ejecutamos el proyecto y listo. Próximamente estaré publicando el video donde muestro paso a paso la realización de este proyecto.
hola: es muy interesante. Pero digamos que quiero que no sea sensible a mayusculas y minusculas? Porque lo interesante de esto es que hace el trabajo por ti, porque sino seria hacer un metodo pero seria mas trabajoso. Gracias.
ResponderBorrarHola Jesus. Para hacerlo de forma tal que no sea sensible a mayúsculas y minúsculas, sólo hay que anteponer "(?i)" en donde obtenemos el texto ingresado en el JTextField dentro del método filtro(). QuedarÃa entonces de la siguiente forma:
ResponderBorrarString filtro = "(?i)"+jTFbuscar.getText();
Espero que te sirva. Saludos
Excelente, me ha servido, muy útil!!
ResponderBorrarMuy bueno el ejemplo!
ResponderBorrarhola podria ayudarme yo intento guardar en un label el valor filtrado mediante un set text pero me da el valor del primer registro de la tabla
ResponderBorrarPara Guardar el valor filtrado dentro de un JLabel, lo que hay que hacer es asignarselo cuando se captura en el método filtro, es decir, después de la lÃnea:
ResponderBorrarString filtro = jTFfiltrar.getText();
Colocamos:
miJLabel.setText(filtro);
Hola me ha servido de mucho su ejemplo, muchas gracias.
ResponderBorrarPero quisiera pedir de su ayuda para recuperar los valores de toda la fila en Strings.
Antes usaba el getSelectedRow Pero ese ahora ya no me sirve.
Con el método getSelectedRow() obtenemos el Ãndice de una fila que esté seleccionada en la Tabla; por tanto, si no hay ninguna fila seleccionada, éste método nos devolverá por defecto el valor -1.
ResponderBorrarPara obtener todos los valores de una fila en Strings debemos hacerlo a través de un ciclo, y podemos recuperarlos desde el JTable o desde el DefaultTableModel. Lo harÃamos de la siguiente forma:
int fila = jTable.getSelectedRow();
String valores = "";
for (int i = 0; i < = jTable.getColumnCount(); i++) {
valores += "" + jTable.getValueAt(fila, i).toString();
valores += " - ";
}
System.out.println(valores);
Lo que hacemos con este ciclo, es recorrer a través de un ciclo for todas las columnas de la Tabla, e ir obteniendo los valores de una fila especÃfica a través del método getValueAt(row, column)
Espero que te haya ayudado
Saludos hermano ...
ResponderBorrardonde estas llamando el método jTFfiltrarKeyTyped???
gracias
En el paso 6, cuando añadimos el evento al JTextField, NetBeans nos genera automáticamente el método jTFfiltrarKeyTyped y agrega el respectivo evento KeyListener al JTextField en donde llama a dicho método. Esto se puede ver dentro del método initComponents() que es auto-generado por NetBeans
ResponderBorrarquiero consultar en un jtable en un rango de fechas con netbeans, alguien me puede explicar como se hace.
ResponderBorrarCuando busco con signo MAS o ASTIRISCO me da error
ResponderBorrarAmigo disculpe y si quisiera reiniciar la consulta y devolver los valores iniciales por medio de un boton?
ResponderBorrarSerÃa inicializar de nuevo el TableRowSorter:
Borrartrsfiltro = new TableRowSorter(tabladatos);
jTdatos.setRowSorter(trsfiltro);
disculpa por mi ignorancia soy nuevo en esto pero en cargar datos como obtengo lo de la base de datos ?
ResponderBorrarArmando, este es un ejemplo que se enfoca en como filtrar unos resultados ya obtenidos dentro de un JTable, y por eso, a modo de ejemplo coloco unos datos quemados que le asigno a la variable datos de tipo Object[][].
BorrarSin embargo, para darte idea, podrÃas hacer lo siguiente:
- Creas una clase donde tengas la lógica de conexión a la base de datos.
- Creas una clase (Que serÃa tu DAO), la cual tendrÃa una asociación de la clase que creaste previamente para la lógica de tu base de datos.
- En tu clase DAO crearÃas el método con la query que retornarÃa tus resultados de la base de datos, y como para este ejemplo se requiere de un valor de tipo Object[][], debes mapear tus resultados en una variable de este tipo y retornarlo mediante el método.
A grandes rasgos, eso es lo que podrÃas hacer para obtener los datos desde la base de datos
sobre esta última respuesta (del 5 de junio de 2019) ¿podrÃas darme un ejemplo de cómo hacerlo? más precisamente la parte de "debes mapear tus resultados en una variable de este tipo y retornarlo mediante el método."
Borrarporque reemplacé el contenido de cagardatos() por
try {
Class.forName("org.sqlite.JDBC");
Connection con = DriverManager.getConnection("jdbc:sqlite:/home/leo/java/Fiesta.db");
String sql = "SELECT * FROM Clientes";
PreparedStatement pst = con.prepareStatement(sql);
ResultSet rs = pst.executeQuery();
jTdatos.setModel(DbUtils.resultSetToTableModel(rs));
}
catch (SQLException ex){
System.out.println("Mensaje:"+ex.getMessage());
} catch (ClassNotFoundException ex)
{
}
pero obviamente no funcionó.
Desde ya, muchas gracias
Desde ya, muchas gracias
Leonardo, después de la lÃnea "jTdatos.setModel(DbUtils.resultSetToTableModel(rs));" deberÃas actualizar el Modelo de datos con esta instrucción:
BorrartableModel.fireTableDataChanged();