Ajuda para limpar a jTable em tempo de execução [RESOLVIDO]

Pessoal eu estou com problema pra limpar a jTable em tempo de execução e gostaria muito da ajuda de vocês. Vou explicar como está a estrutura do programa aqui. Tem uma classe que cadastra e consulta clientes que é a classe principal. A consulta é exibida na jTable seja digitando um nome no campo de busca ou apenas clicando no botão Pesquisar que exibe tudo na jTable. E tem outras duas classes para gerenciar essa jTable. Uma classe é pra representar os dados que vai ser exibido na jTable que é onde foi declarado os atributos e métodos referente aos campos do banco e a outra classe cria a jTable extendendo do AbstractTableModel.

E na classe principal que eu faço a consulta dos dados do banco, quando eu efetuo a consulta, os dados são exibidos na jTable, só que quando eu altero ou deleto um registro, para a tabela atualizar eu tenho que fechar o frame e abrir de novo e efetuar novamente a consulta pra jTable atualizar. Mas eu gostaria de atualizar em tempo de execução sem precisar fechar o programa. Vou mostrar o código da classe que cria a jTable.

[code]public class ClienteModel extends AbstractTableModel {

private static final long  serialVersionUID = 1L;  

// Lista de clientes do modelo da JTable

public final List<Cliente> clientes = new ArrayList<Cliente>();


public int getColumnCount(){
	return 3;
}

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

 public Object getValueAt(int rowIndex, int columnIndex) {  
	       Cliente cliente = clientes.get(rowIndex);  
	       switch (columnIndex) {  
	          
	          case 0:  
	             return cliente.getIdcliente();  
	       	  case 1:  
	             return cliente.getCliente();  
	                   		          
	          case 2:  
		         return cliente.getTelefone(); 
	          
	           		             
	          default:  
	             return null;  
	       }  
	    }
 
  public String getColumnName(int column) {  
	        switch (column) {  
	           
	        	case 0:  
	              return "Código";  
	           	
	        	case 1:  
	              return "Cliente";  
	           
	        	case 2:  
	              return "Telefone";  
	             
	           
	              
	           default:  
	              return null;  
	        }  
	     }  
	  }  
[/code]

Agora o código que fica dentro do evento do botão “Pesquisar”.

[code]try{

					String pesquisa = jTextFieldPesquisar.getText(); //aqui é uma variavel que armazena o dado digitado no campo de busca
					
					st = conexao.conectar().createStatement();
					
										
					sql = "select * from cliente where Cliente like '"+ "%" + pesquisa + "%" + "'";
					
					ClienteModel modelo = (ClienteModel) jTable.getModel();
											
					rs = st.executeQuery(sql);
					while(rs.next()) {
					
					     modelo.clientes.add(new Cliente(rs));  
					 }  
					

					jTable.updateUI();  
					
					

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

[/code]

Esse método jTable.updateUI(); não atualiza se eu colocar depois no evento do botão Excluir ou Alterar. Ele só funciona aqui no botão Pesquisar quando eu clico nesse botão para exibir os dados na tabela.

Agora tem um outro problema. Toda vez que eu clicar no botão Consultar, vai exibir novamente os dados exibidos na primeira vez. Por exemplo, eu clico uma vez e vai exibir 10 registros, do 1 ao 10. Se eu clico de novo, vai exibir lá embaixo a partir da linha 11 esses 10 registros de novo, mas contando do 1 ao 10 novamente. Ele não atualiza quando eu efetuo a consulta de novo. Ele vai populando a tabela sem atualizar não importando quantas vezes eu efetuar a consulta.

Então tudo faz parte do mesmo problema que é limpar a jTable em tempo de execução. Aguardo a ajuda de vocês então. Obrigado.

Ele reproduz o que tem no model. Portanto, adicione um método de limpeza no seu model:

public void clear() { clientes.clear(); fireTableDataChanged(); }

Outra coisa. É uma péssima prática deixar sua lista publica no model e adicionar clientes nela diretamente. Até porque, após adicionar um cliente, você deveria lançar o evento de que uma linha foi adicionada. Caso contrário, pode ocorrer de sua tabela não desenhar o cliente. Então, deixe sua lista private (como todo atributo deve ser) e adicione também esses métodos:

[code]
public void add(Cliente cliente) {
clientes.add(cliente);
fireTableRowsInserted(clientes.size()-1, clientes.size()-1);
}

public void remove(Cliente cliente) {
int index = clientes.indexOf(cliente);
if (index == -1) {
return;
}
clientes.remove(index);
fireTableRowsDeleted(index, index);
}[/code]

Com esses métodos, não será necessário chamar updateUI(). Na verdade, sempre desconfie quando estiver chamando updateUI(). Numa aplicação swing tradicional, esse método jamais deveria ser chamado diretamente.

Seu try então fica assim:

try{   
   Connection conn = null;                        
   PreparedStatement st = null;
   try {
      String pesquisa = jTextFieldPesquisar.getText(); //aqui é uma variavel que armazena o dado digitado no campo de busca  
      conn = conexao.conectar();
      st = conn.prepareStatement("select * from cliente where Cliente like ?");  
      st.setString(1, "%" + pesquisa + "%");
      ClienteModel modelo = (ClienteModel) jTable.getModel();  
      rs = st.executeQuery();  
      modelo.clear(); //Limpa a tabela primeiro
      while(rs.next()) {  
         modelo.add(new Cliente(rs));
      }
   }  finally {
       if (st != null) st.close();
       if (conn != null) conn.close();
   }
}catch (Exception ex) {  
     throw new RuntimeException(ex);
}  

Vini, testei aqui e deu essa exceção:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.sql.SQLException: No parameters defined during prepareCall() at cliente.CadastroCliente$12.actionPerformed(CadastroCliente.java:1173) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) Caused by: java.sql.SQLException: No parameters defined during prepareCall() at com.mysql.jdbc.ServerPreparedStatement.getBinding(ServerPreparedStatement.java:1175) at com.mysql.jdbc.ServerPreparedStatement.setString(ServerPreparedStatement.java:554) at cliente.CadastroCliente$12.actionPerformed(CadastroCliente.java:1162) ... 25 more

Só pra ver se ajuda, no construtor da jTable tem essa linha: jTable.setModel(new ClienteModel());

E sobre a lista pública, você quer dizer nessa linha né?

Eu já coloquei private final…

Só pra voce ver como ficou aqui então no bloco do try no evento do botão. Precisou fazer um cast ali na linha de conexão. Eu deixei comentado. E também colocar uma chave a mais no linha onde está finally.

try{ Connection conn = null; PreparedStatement st = null; try { String pesquisa = jTextFieldPesquisar.getText(); //aqui é uma variavel que armazena o dado digitado no campo de busca conn = (Connection) conexao.conectar(); // precisou fazer um cast. st = conn.prepareStatement("select * from cliente where Cliente like '%?%'"); st.setString(1, pesquisa); ClienteModel modelo = (ClienteModel) jTable.getModel(); rs = st.executeQuery(); modelo.clear(); //Limpa a tabela primeiro while(rs.next()) { modelo.add(new Cliente(rs)); }} finally { if (st != null) st.close(); if (conn != null) conn.close(); } }catch (Exception ex) { throw new RuntimeException(ex); }

Eu já uso uma classe de conexão, aí quando eu quero conectar, eu chamo o método conectar() com o objeto “conexao”. Será que pode ter alguma coisa a ver com esse erro?

O cast não deveria ser necessário. Verifique se você deu o import correto no seu arquivo. O import deve ser o mesmo que está na sua classe de conexão.
Aquele finally fecha a conexão. Se sua classe mantém apenas 1 conexão aberta, pode ser isso.

Entretanto, o ideal é sempre trabalhar com a conexão e os statements fechados por padrão. Caso contrário seu sistema pode apresentar falhas, como falta de memória ou perdas de conexão com o banco.

Quanto ao erro, é pq o like não deve ir com ‘’, já corrigi o código ali em cima.

Vini, deu certo agora. Valeu mesmo pela ajuda. Só que eu tive que deixar o cast. O import estava tudo certo mesmo. Sobre a conexão aberta, nos trechos de código que eu uso o método de conexão eu nunca fecho a conexão. Todas ficam abertas. Deve ser por isso né? Depois eu corrijo isso. Mas está tudo correto agora, funcionando certinho mesmo.

Deixa eu te perguntar só mais uma coisa. Sem querer abusar de você. Esse método model.clear(); eu posso usar em outras partes do código não posso? Eu tentei usar no evento do botão “Excluir”, que após deletar um registro a tabela atualizar usando esse método. E também colocar em outros botões como o Cancelar, que quando eu clico nesse botão, sai da tela de consulta e volta pra aba de cadastro. É que esse programa aqui tem duas abas, uma de cadastro e outra de consulta que é essa tela que exibe a jTable. E como esse objeto modelo foi instanciado dentro de um try, eu tirei ele do try pra instanciar fora desse try pro objeto ser reconhecido na classe toda, mas gerou a exceção NullPointerException apontando pra mesma linha que eu instanciei esse objeto quando eu executo a classe. ClienteModel modelo = (ClienteModel) jTable.getModel();

Eu teria que inicializar esse objeto pra isso funcionar?

Edit: eu estava tentando colocar o método de limpar aqui nesse código que fica no evento do botão Excluir.

[code]String valorSelecionado = jTable.getValueAt(jTable.getSelectedRow(),jTable.getSelectedColumn()).toString();
int status = JOptionPane.showConfirmDialog(null,“Deseja excluir o registro selecionado?”,“Atenção”,JOptionPane.YES_NO_OPTION);
if (status == JOptionPane.YES_OPTION) {

				    	try{
				    	st = conexao.conectar().createStatement();
				    	st.executeUpdate("DELETE FROM cliente WHERE IDCliente = "+valorSelecionado);
				    	JOptionPane.showMessageDialog(null, "Registro excluído com sucesso!");
				    	//modelo.clear();      // método para limpar a tabela
				  
				    	  
				    	
				    	}catch (Exception ex){
							ex.printStackTrace();
						}[/code]

O clear limpa a tabela toda. Se você quiser remover só um registro, use o remove.

Talvez fosse uma boa você implementar um remove que remova por índice. Aí vc pode passar o getSelectedRow() para ele.

Eu posso usar aquele método remove da classe TableModel? Eu tentei usar aquele método de várias maneiras mas não consegui. O código que eu estou usando agora pra Excluir é assim:

[code]int linha = jTable.getSelectedRow();
codigo = jTable.getValueAt(linha, 0);// a variável codigo é do tipo Object.

try{
ClienteModel modelo = (ClienteModel) jTable.getModel();
st = conexao.conectar().createStatement();
st.executeUpdate("DELETE FROM cliente WHERE IDCliente = "+codigo);
[/code]

Aí eu tentei linha.remove(); modelo.remove(); modelo.remove(linha); modelo.remove(codigo), modelo.remove(null), mas sem chance até agora.

Como eu falei, você tem que adaptar o método. Você não tentou entender o que ele faz?

Um método remove por linha seria assim.

public Cliente remove(int linha) { if (linha &lt; 0 || linha &gt;= clientes.size()) { return null; } Cliente cliente = get(linha); clientes.remove(linha); fireTableRowsDeleted(linha, linha); return cliente; }

Se você implementar esse método, aquele outro pode ser substituído por:

public void remove(Cliente cliente) {  
    remove(clientes.indexOf(cliente));
 }  

É uma boa também você implementar um método get(int linha) no seu TableModel e parar de usar o getValueAt(). Isso te dá mais liberdade de trocar as colunas de lugar, depois.

public Cliente get(int linha) { return clientes.get(linha); }

Vini é que eu to meio perdido com esses métodos. Esses 3 métodos eu devo colocar todos na Table Model?

Sim, todos no TableModel.

Coloquei mas tá dando erro nessa linha que está grifado.

Fala que esse método deve retornar o resultado do tipo Cliente.

É só colocar um
return Cliente;
no final.

Mas… você não conseguia corrigir isso sozinho não?

[quote=ViniGodoy]É só colocar um
return Cliente;
no final.

Mas… você não conseguia corrigir isso sozinho não?[/quote]

Agora deu certo. Eu marquei bobeira ali mesmo, deu um branco. Coloquei “cliente” como tipo de retorno e lá na classe principal eu coloquei assim:

Como você deve ter percebido, eu não manjo nada mesmo de Java. Esse programa que eu estou fazendo é pro meu TCC. Por incrivel que pareça eu estou no quarto ano mas eu não manjo nada mesmo pois eu nunca fiz estágio e nunca fui de praticar em casa, por isso eu fico meio perdido. Então agora eu estou apanhando pra fazer o TCC. Mas só estou fazendo com ajuda mesmo, pois sozinho eu não iria conseguir. Mas já estou no final do projeto.

Muito obrigado pela ajuda. Você me ajudou bastante. :wink:

Abraços.

Estranho, pq o model que você apresentou está no caminho certo. A maioria faz a besteira de começar pelo DefaultTableModel, então imaginei que você manjasse um pouco mais.

É importante que você entenda como o model funciona. Ele é quem diz para a tabela o que deve ser desenhado. E a tabela, só faz o desenho em si.

Eu pedi ajuda num outro forum sobre a TableModel e foi uma pessoa que fez pra mim essa classe. Eu não entendo muito os conceitos mesmo de TableModel mas vou estudar isso mais a fundo.

Até mais então. Valeu.