Pesquisa em jTable

Olá galera, estou tento alguns problemas em relação a utilização da jTable. Estou finalizando um projeto de uma agenda de contatos e resolvi colocar na tela onde mostra a jTable com os dados cadastrados no banco de dados um jTextField e um botão para fazer a pesquisa. O problema é que da forma que fiz, está acontecendo a pesquisa, mas não da forma correta, ou seja, se eu digitar no campo pesquisa a Letra M, deveria ser listado todos os contatos iniciados com a letra M, o que não acontece. Estão sendo listados apenas 2 registros, de forma que, deveria ser listados 5, pois é o total de registros cadastrados no banco iniciados com essa letra. Além disso, se for digitado o nome Marcelo, por exemplo, a pesquisa não acha. Sinceramente eu não sei onde estou errando. Abaixo está o código que estou utilizando na aplicação. Alguém pode me ajudar ?

Método para a pesquisa

public void pesqRegistro(String value) {

    ResultSets = new ArrayList<String[ ]>( );
    

    JTextField[ ] tf= campos(    ); // não precisa

    String SQL="SELECT registro,nome,telefone FROM registros WHERE nome LIKE ' " + value + "%' " ;

    ResultSet res;

    try{
        res=stmt.executeQuery(SQL);
        while(res.next( ) ){
        String[ ] row = {res.getString("registro"),res.getString("nome"),res.getString("telefone")};
        ResultSets.add(row);
        
        tabela.setResult(res);
                    
       }
                  
        tabela.fireTableStructureChanged();

       }catch(SQLException ex){
        ex.printStackTrace();

      }

}


Evento do botão pesquisar

private void jbutaoPesqActionPerformed(java.awt.event.ActionEvent evt) {

    // TODO add your handling code here:

   pesqRegistro( tfPesq.getText( ) );
}

Essa linha deveria estar fora do while:

Espero que você não esteja usando o DefaultTableModel. E seria uma boa você usar o PreparedStatement e evitar aquela concatenação de Strings perigosa ali.

Além disso, ao postar códigos, siga essa dicas:
http://www.guj.com.br/posts/list/50115.java

Não estou usando defaultTableModel, criei um TableModel. Em relação tabela.setResult(res) já testei fora do enquanto e continua dando o mesmo resultado.
Fiz um teste simples para ver se a pesquisa está retornando os valores corretamente, por exemplo criei um contador para retornar o número de registros em cada pesquisa e deu certo. O problema está em relação a visualização dos dados dessa pesquisa na jTable. Parece que ela não está conseguindo montar a visualização desses dados, o que posso fazer.

Ainda estou esperando vc postar a dúvida que vc me enviou na MP aqui, para que continuemos a evoluir esse tópico.

Em relação ao código postado anteriormente, fiz algumas modificações para tentar conseguir visualizar os dados da pesquisa do banco de dados na jTable e não consegui. Para o projeto agenda, criei o próprio modelo de tabela - TableModel, nesse caso chamado de TabelaAgenda e também criei uma Lista, um método para mostrar os dados da pesquisa na JTable e nada. Tem uma variável tabela que é do tipo TabelaAgenda, onde faço com que ela receba os dados da Lista para ser visualizadas na jTable, mas não funciona.
Fiz um teste para ver se a consulta estava retornando corretamente os resultados da pesquisa que viram do banco, só que para serem mostrados no console e tudo funcionou corretamente. O problema está em mostrar esses dados na jTable. Segue abaixo o meu modelo (TabelaAgenda) e os códigos para que os dados sejam mostrados na jTable.

TabelaAgenda:


import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author marcelo
 */
public class TabelaAgenda extends AbstractTableModel {
    private int rownum;
    private static final String[] colNames={"Registro","Nome","Telefone"};
    private ArrayList<String[]>ResultSets;
    private ResultSetMetaData metaData;
    private Statement stmt;

    
    public TabelaAgenda(ResultSet rs)throws SQLException {
        setResult(rs);
       
    }



    public int getRowCount() {
        return ResultSets.size();
    }

    public int getColumnCount() {
        return colNames.length;
    }
    public String getColumnName(int param){
        return colNames[param];
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        String[]row = ResultSets.get(rowIndex);
        return row[columnIndex];
    }

    public void setResult(ResultSet rs) throws SQLException {
        ResultSets=new ArrayList<String[]>();

        while (rs.next()){
            String[]row = {rs.getString("registro"),rs.getString("nome"),rs.getString("Telefone")};
            ResultSets.add(row);
        }
        fireTableStructureChanged();
       

    }

    public void deletRow(int row){
        ResultSets.remove(row);
        fireTableRowsDeleted(row,row);

    }

   } 

Classe Agenda: Nessa classe ficam todos os métodos de acesso ao banco de dados


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

/**
 *
 * @author marcelo
 */
public class Agenda extends javax.swing.JFrame {

    private TabelaAgenda tabela;
    private Statement stmt;
    private Conexao conexao;
    private Connection conn;
    private String rowId;
    private boolean novo;
    private Object tamanhoFrame;
    private ArrayList<String[]> ResultSets;
    private String value;
    private Connection con;
    List<Contatos> contato;
    
   
    
      private ResultSet getResults(){
        ResultSet rs =null;
        try{
            rs=stmt.executeQuery("select*from registros ORDER BY registro");
        }catch(SQLException e){}
        return rs;
    }

    public List<Contatos> getList(String nome) throws SQLException{
        String sql ="SELECT registro,nome,telefone FROM registros WHERE nome LIKE ?";
        PreparedStatement stm = conn.prepareStatement(sql);
        stm.setString(1,nome);
        ResultSet rs = stm.executeQuery();

        List<Contatos> minhaLista = new ArrayList<Contatos>();

        while(rs.next()){
            Contatos tab = new Contatos();
            tab.setRegistro(Long.valueOf(rs.getString("registro")));
            tab.setNome(rs.getString("nome"));
            tab.setTelefone(rs.getString("telefone"));
            minhaLista.add(tab);

          
        }
        rs.close();
        stm.close();
        return minhaLista;
   
    }

    private void listarContatos() throws SQLException {
        Agenda agend =new Agenda();
        contato=agend.getList(tfPesq.getText() + "%");
        mostrarPesquisa(contato);

    }

    private void mostrarPesquisa(List<Contatos> contato) throws SQLException {
        if(contato.size() == 0){
          JOptionPane.showMessageDialog(null, "Dado não encontrado na pesquisa");
        }else{
            String [] linha = new String[]{null,null,null};
            for(int i=0;i< contato.size();i++){

          // tabela.addTableModelListener(jTable1);
            tabela.setValueAt(contato.get(i).getRegistro(),i, 0);
            tabela.setValueAt(contato.get(i).getNome(),i, 1);
            tabela.setValueAt(contato.get(i).getTelefone(),i, 2);
        }
            tabela.fireTableDataChanged();
    }

  }
        
}

Também criei a classe contatos que possui tos os métos set e get. O método mostrarPesquisa foi criado para setar os valores da pesquisa na jtable. Tentei fazer dessa forma, baseado em um método para defaultTableModel, mas não deu certo, apesar de a variável tabela representar a TabelaAgenda. Contudo, a jtable ñão consegue receber esses novos dados. Até agora ninguém, inclusive eu, consegui descobrir o que está acontencendo.
No evento do botão pesquisar chamo o método listarContatos.

Se você criou a classe contato, está na hora de usa-la. Primeiro vamos organizar seu sistema, depois vemos a questão do TableModel.

A primeira coisa que você tem que fazer, é criar a classe de contato. Isso, você comentou que já fez.
Em seguida, você precisa criar uma classe que carregue contatos do banco. Normalmente é uma classe separada, chamada ContatoDao. Ela vai ter um método assim:

public List&lt;Contato&gt; carregarContatos() { //Coloque aqui a query para o banco }

Outras versões, como carregarContatoPorNome(String nome), também podem existir no DAO.

Com a lista de contatos na mão, aí sim, chega a hora de montar seu TableModel. Dentro do TableModel, você terá um List<Contato> e não um ArrayList<String[]>. Seu tablemodel já estava no caminho certo, mas vc deve usar sempre classes de negócio e não String[].

O método que carrega contatos do banco, também já foi criado, no caso:

public List<Contatos> getList(String nome) throws SQLException{   
        String sql ="SELECT registro,nome,telefone FROM registros WHERE nome LIKE ?";   
        PreparedStatement stm = conn.prepareStatement(sql);   
        stm.setString(1,nome);   
        ResultSet rs = stm.executeQuery();   
  
        List<Contatos> minhaLista = new ArrayList<Contatos>();   
  
        while(rs.next()){   
            Contatos tab = new Contatos();   
            tab.setRegistro(Long.valueOf(rs.getString("registro")));   
            tab.setNome(rs.getString("nome"));   
            tab.setTelefone(rs.getString("telefone"));   
            minhaLista.add(tab);   
  
             
        }   
        rs.close();   
        stm.close();   
        return minhaLista;   
     
    }   

E esse metodo está na classe Agenda que possui todos os métodos para inserção,atualização, exclusão e pesquisa no banco de dados, como se fosse o ContatoDao que vc está falando. No caso, eu terei que substituir essa lista criada acima? se eu utilizá-la e criar uma outra dentro do meu TableModel(TabelaAgenda) funcionará ?

Dê uma olhada agora na classe do Erik Yuzo (a primeira da minha assinatura). Apenas mudei o original dele que era “Socio” para “Contato”:

[code]import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

/**

  • Implementação de Table Model para exibir os Sócios.

  • @author Eric Yuzo
    */
    public class ContatoTableModel extends AbstractTableModel {

    private static final long serialVersionUID = 1L;

    /* Lista de Sócios que representam as linhas. */
    private List<Contato> linhas;

    /* Array de Strings com o nome das colunas. */
    private String[] colunas = new String[] {
    “Nome”, “E-mail”, “Telefone fixo”, “Telefone celular”};

    /* Cria um ContatoTableModel vazio. */
    public ContatoTableModel() {
    linhas = new ArrayList<Contato>();
    }

    /* Cria um ContatoTableModel carregado com

    • a lista de sócios especificada. */
      public ContatoTableModel(List<Contato> listaDeContatos) {
      linhas = new ArrayList<Contato>(listaDeContatos);
      }

    /* Retorna a quantidade de colunas. */
    @Override
    public int getColumnCount() {
    // Está retornando o tamanho do array "colunas".
    // Mas como o array é fixo, vai sempre retornar 4.
    return colunas.length;
    }

    /* Retorna a quantidade de linhas. */
    @Override
    public int getRowCount() {
    // Retorna o tamanho da lista de sócios.
    return linhas.size();
    }

    /* Retorna o nome da coluna no índice especificado.

    • Este método é usado pela JTable para saber o texto do cabeçalho. */
      @Override
      public String getColumnName(int columnIndex) {
      // Retorna o conteúdo do Array que possui o nome das colunas
      // no índice especificado.
      return colunas[columnIndex];
      };

    /* Retorna a classe dos elementos da coluna especificada.

    • Este método é usado pela JTable na hora de definir o editor da célula.
    • Como todos os campos deste model são Strings (nome, e-mail e fones),
    • o retorno será sempre a classe String. */
      @Override
      public Class<?> getColumnClass(int columnIndex) {
      return String.class;
      };

    /* Retorna o valor da célula especificada

    • pelos índices da linha e da coluna. */
      @Override
      public Object getValueAt(int rowIndex, int columnIndex) {
      // Pega o sócio da linha especificada.
      Contato contato = linhas.get(rowIndex);

      // Retorna o campo referente a coluna especificada.
      // Aqui é feito um switch para verificar qual é a coluna
      // e retornar o campo adequado. As colunas são as mesmas
      // que foram especificadas no array "colunas".
      switch (columnIndex) {
      case 0: // Primeira coluna é o nome.
      return contato.getNome();
      case 1: // Segunda coluna é o e-mail.
      return contato.getEmail();
      case 2: // Terceira coluna é o telefone fixo.
      return contato.getTelefoneFixo();
      case 3: // Quarta coluna é o telefone celular.
      return contato.getTelefoneCelular();
      default:
      // Se o índice da coluna não for válido, lança um
      // IndexOutOfBoundsException (Exceção de índice fora dos limites).
      // Não foi necessário verificar se o índice da linha é inválido,
      // pois o próprio ArrayList lança a exceção caso seja inválido.
      throw new IndexOutOfBoundsException("columnIndex out of bounds");
      }
      }

    /* Seta o valor da célula especificada

    • pelos índices da linha e da coluna.
    • Aqui ele está implementado para não fazer nada,
    • até porque este table model não é editável. */
      public void setValueAt(Object aValue, int rowIndex, int columnIndex) {};

    /* Retorna um valor booleano que define se a célula em questão

    • pode ser editada ou não.
    • Este método é utilizado pela JTable na hora de definir o editor da célula.
    • Neste caso, estará sempre retornando false, não permitindo que nenhuma
    • célula seja editada. */
      @Override
      public boolean isCellEditable(int rowIndex, int columnIndex) {
      return false;
      }

    ////////////////////////////////////////////////////////////
    // Os métodos declarados até aqui foram as implementações //
    // de TableModel, que são continuamente utilizados //
    // pela JTable para definir seu comportamento, //
    // por isso o nome Table Model (Modelo da Tabela). //
    // //
    // A partir de agora, os métodos criados serão //
    // particulares desta classe. Eles serão úteis //
    // em algumas situações. //
    ////////////////////////////////////////////////////////////

    /* Retorna o sócio da linha especificada. */
    public void getContato(int indiceLinha) {
    linhas.get(indiceLinha);
    }

    /* Adiciona um registro. */
    public void addContato(Contato contato) {
    // Adiciona o registro.
    linhas.add(contato);

     // Pega a quantidade de registros e subtrai um para achar
     // o último índice. É preciso subtrair um, pois os índices
     // começam pelo zero.
     int ultimoIndice = getRowCount() - 1;
    
     // Reporta a mudança. O JTable recebe a notificação
     // e se redesenha permitindo que visualizemos a atualização.
     fireTableRowsInserted(ultimoIndice, ultimoIndice);
    

    }

    /* Remove a linha especificada. */
    public void removeContato(int indiceLinha) {
    // Remove o sócio da linha especificada.
    linhas.remove(indiceLinha);

     // Reporta a mudança. O JTable recebe a notificação
     // e se redesenha permitindo que visualizemos a atualização.
     fireTableRowsDeleted(indiceLinha, indiceLinha);
    

    }

    /* Adiciona uma lista de sócios ao final dos registros. */
    public void addListaDeContatos(List<Contato> contatos) {
    // Pega o tamanho antigo da tabela.
    int tamanhoAntigo = getRowCount();

     // Adiciona os registros.
     linhas.addAll(contatos);
    
     // Reporta a mudança. O JTable recebe a notificação
     // e se redesenha permitindo que visualizemos a atualização.
     fireTableRowsInserted(tamanhoAntigo, getRowCount() - 1);
    

    }

    /* Remove todos os registros. */
    public void limpar() {
    // Remove todos os elementos da lista de sócios.
    linhas.clear();

     // Reporta a mudança. O JTable recebe a notificação
     // e se redesenha permitindo que visualizemos a atualização.
     fireTableDataChanged();
    

    }

    /* Verifica se este table model está vazio. */
    public boolean isEmpty() {
    return linhas.isEmpty();
    }

}[/code]

Acho que com isso vc pode ter uma idéia de como ficará o seu TableModel.
Note que o model só se preocupa em como apresentar os dados.

Irei fazer as devidas alterações no meu modelo TableModel. Contudo gostaria de saber se posso continuar utilizando a lista da forma que criei acima na classe Agenda, que seria o " contatoDao" que vc se refere. Já de acordo com as instruções que vc me passou terei que criar 1 ou 2 metodos do tipo lista na classe Agenda. O primeiro sem passagem de parâmetro para listar todos o dados da lista e outro passando como parâmetro o nome do “cliente” cadastrado na agenda para ser listado somente seus dados na jTable?
Desta forma:

Public List<Contatos>carregarContatos() throws SQLException{  

public List<Contatos>carregarContatosPorNome(String nome) throws SQLException{
   1. public List<Contatos> getList(String nome) throws SQLException{     
   2.         String sql ="SELECT registro,nome,telefone FROM registros WHERE nome LIKE ?";     
   3.         PreparedStatement stm = conn.prepareStatement(sql);     
   4.         stm.setString(1,nome);     
   5.         ResultSet rs = stm.executeQuery();     
   6.     
   7.         List<Contatos> minhaLista = new ArrayList<Contatos>();     
   8.     
   9.         while(rs.next()){     
  10.             Contatos tab = new Contatos();     
  11.             tab.setRegistro(Long.valueOf(rs.getString("registro")));     
  12.             tab.setNome(rs.getString("nome"));     
  13.             tab.setTelefone(rs.getString("telefone"));     
  14.             minhaLista.add(tab);     
  15.     
  16.                
  17.         }     
  18.         rs.close();     
  19.         stm.close();     
  20.         return minhaLista;     
  21.        
  22.     }    

O ContatoDao seria a classe que pega contatos do banco e transforma na lista da classe contato. No caso, no seu sistema, quem está desempenhando esse papel é a Agenda.

Não tem problema usa-la. O que vc vai fazer, na hora de preencher na tabela, é simplesmente pegar da agenda e trocar o model do seu JTable:

List&lt;Contatos&gt; contatos = agenda.getList("M"); ContatoTableModel model = new ContatoTableModel(contatos); tblContato.setModel(model);

vou alterar o meu projeto de acordo com as suas instruções e depois posto os resultados. Obrigado.

pq nao?

Por que não o que?

hehe, acabei de ver um erro no meu exemplo lendo este tópico.

public void getContato(int indiceLinha) { linhas.get(indiceLinha); } O correto seria retornar o contato:

public Contato getContato(int indiceLinha) { return linhas.get(indiceLinha); }
Já corrigi no outro tópico também.

isso percebi tambem… esse é um erro desgraçado que so matando mesmo…

Antes que eu faça as devidas modificações no meu projeto conforme as instruções que recebi, gostaria de de esclarecer duas dúvidas:

1ª - O código abaixo é usado para preencher a jTable com esse novo modelo, certo. A pergunta é a seguinte, onde devo inserir esse código, na Classe Agenda onde ficam todos os métodos de acesso ao banco de dados, nas propriedades da jTable, no caso, código personalizado -pré inicialização ou dentro da classe ContatoTableModel ?

List<Contatos> contatos = agenda.getList("M");   
ContatoTableModel model = new ContatoTableModel(contatos);   
tblContato.setModel(model);  

2ª - No trecho de código abaixo na parte agenda.getList(“M”), o caracter M é o parâmentro usado para trazer os resultados da pesquisa, no caso que possuem a letra M no nome ?

List<Contatos> contatos = agenda.getList("M"); 

Vini, vc ainda não me respondeu a última dúvida postada, no entanto encontrei mais um problema em relação a instrução que vc me passou. No código abaixo vc diz que deve-se pegar os contatos da agenda, só que na classe Agenda como vc já sabe eu criei a lista, só que quando eu digito Agenda., o NetBeans não encontra o método da lista criada public List<Contatos> getList() e pede para criar o método getList na classe Agenda.

view plaincopy to clipboardprint?

   1. List<Contatos> contatos = agenda.getList("M");     
   2. ContatoTableModel model = new ContatoTableModel(contatos);     
   3. tblContato.setModel(model);    

Quando cria-se o método getList o NetBeans cria da seguinte forma:

private static List<Contatos>getList(){

só que eu estou utlizando o preparedStatement e da forma como o netBeans criou este método da Lista como static ele indica o seguinte erro no uso do preparedStatement:
non-variable static cannot… de que forma posso corrigir este problema ?

Sim, vc vai precisar fazer algo como

Agenda agenda = new Agenda(); List&lt;Contato&gt; contatos = agenda.getList();

E no caso anterior, o parâmetro M servia pro que vc descreveu mesmo.

Tudo bem, mas onde devo colocar essa parte do código, nas propriedades da jtable ou diretamente na classe Agenda:

[code]
Agenda agenda = new Agenda()

  1. List contatos = agenda.getList(“M”);
  2. ContatoTableModel model = new ContatoTableModel(contatos);
  3. tblContato.setModel(model);
    [/code].

Fiz as alterações como criar da forma como o netBeans estava pedindo a lIsta:

public static List<Contatos> getLista (){

e coloquei esse trecho de código na propriedade da jtable( código personalizado)

  1. List<Contatos> contatos = agenda.getList("%" + tfPesq.getText()+"%");    
   2. ContatoTableModel model = new ContatoTableModel(contatos);     
   3. tblContato.setModel(model);  

e refiz o meu Tablemodel de acordo com exemplo que vc me passou e mesmo assim, a jtable não me mostrou o resultado com dados da pesquisa. o que ela está mostrando é somente todos os contatos já cadastrados no banco e não o que estamos pesuisando.

Poste o método getList() que vc está usando. O problema não está no JTable.