Por favor, activa JavaScript y desactiva tu adblock para este sitio

El Javatar

Blog dedicado a la Programación en Java, C, PHP, Phyton, HTML, SQL y Mucho Más

miércoles, 16 de abril de 2014

Como Filtrar los Resultados de una Consulta en un JTable

Como Filtrar los Resultados de una Consulta en un JTable
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:

Estructura Proyecto Interfaz Grafica - Como Filtrar los Resultados de una Consulta en un JTable

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.

Interfaz Grafica - Como Filtrar los Resultados de una Consulta en 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:

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:

Datos Cargados - Como Filtrar los Resultados de una Consulta en un JTable

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:

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.

18 comentarios:

  1. 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.

    ResponderBorrar
  2. Hola 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:

    String filtro = "(?i)"+jTFbuscar.getText();

    Espero que te sirva. Saludos

    ResponderBorrar
  3. hola 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

    ResponderBorrar
  4. Para 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:

    String filtro = jTFfiltrar.getText();

    Colocamos:

    miJLabel.setText(filtro);

    ResponderBorrar
  5. Hola me ha servido de mucho su ejemplo, muchas gracias.
    Pero 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.

    ResponderBorrar
  6. 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.

    Para 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

    ResponderBorrar
  7. Saludos hermano ...

    donde estas llamando el método jTFfiltrarKeyTyped???

    gracias

    ResponderBorrar
  8. 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

    ResponderBorrar
  9. quiero consultar en un jtable en un rango de fechas con netbeans, alguien me puede explicar como se hace.

    ResponderBorrar
  10. Cuando busco con signo MAS o ASTIRISCO me da error

    ResponderBorrar
  11. Amigo disculpe y si quisiera reiniciar la consulta y devolver los valores iniciales por medio de un boton?

    ResponderBorrar
    Respuestas
    1. Sería inicializar de nuevo el TableRowSorter:

      trsfiltro = new TableRowSorter(tabladatos);
      jTdatos.setRowSorter(trsfiltro);

      Borrar
  12. disculpa por mi ignorancia soy nuevo en esto pero en cargar datos como obtengo lo de la base de datos ?

    ResponderBorrar
    Respuestas
    1. Armando, 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[][].

      Sin 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

      Borrar
    2. 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."
      porque 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

      Borrar
    3. Leonardo, después de la línea "jTdatos.setModel(DbUtils.resultSetToTableModel(rs));" deberías actualizar el Modelo de datos con esta instrucción:
      tableModel.fireTableDataChanged();

      Borrar