Verificar linha preenchida no JTable

23 respostas
evertonsilvagomesjav

Pessoal como eu verifico se minha linha esta preenchida no JTable.? Por exemplo se minha primeira linha estiver preenchida eu adiciono os dados na segunda e assim por diante. No meu TableModel eu passo um List no construtor e uso essa lista no metodo getValueAt, e então ele sobreescreve a primeira linha em vez de ir adicionando dinamicamente.

23 Respostas

ViniGodoy

Crie um método add(User user) e nesse método, faça um add na sua lista.

evertonsilvagomesjav

Vini, desculpa ignorancia mas nao entendi bem, esse método add vou criar onde no model? E esse add vou passar um objeto usuario daí como vou setar eles la linha do JTable sem o getValueAt?

ViniGodoy

No model. Dentro do seu model existe um List<User> certo?

Então vc faz assim:

public void add(User usuario) { lista.add(usuario); fireTableRowsInserted(lista.size()-1, lista.size()-1); }

Isso vai adicionar o usuário ao final da sua lista, e avisar o JTable que tem linha nova para ele pintar.

evertonsilvagomesjav
ViniGodoy:
No model. Dentro do seu model existe um List<User> certo?

Então vc faz assim:

public void add(User usuario) {
   lista.add(usuario);
   fireTableRowsInserted(lista.size()-1, lista.size()-1);
}

Isso vai adicionar o usuário ao final da sua lista, e avisar o JTable que tem linha nova para ele pintar.

sim mas como vou fazer pra JTable chamar esse método? Por que o getValueAt o proprio Table o faz e este método add como faço?

no meu cod ta assim:

if(e.getSource() == this.buttonCadastrar){
			
			if(!this.text.getText().isEmpty()){
			
				User user = new User();
				
				List<User> list = new ArrayList<User>();
				
				user.setNome(this.text.getText());
				user.setTel(this.textTel.getText());
				
				list.add(user);
										
				JOptionPane.showMessageDialog(null,"Cadastro concluido com sucesso:\n" +
										  	  this.text.getText() +" " +this.textTel.getText());
				
						
				
				
				this.table.setModel(new ModelTable(list)); // AQUI CHAMO MEU MODEL....
								
				
			}else{
				
				JOptionPane.showMessageDialog(null, "Não  pessoas para cadastrar.");
				
			}
			
			return;
		
		}
ViniGodoy

Ali você está criando um novo model. Você só deve criar o model uma única vez, quando criar a tela. Naquele local você deveria só fazer:

modelTable.add(user);

Note que vc também está criando uma nova lista de usuários a cada usuário inserido. E isso também não está certo.

evertonsilvagomesjav
ViniGodoy:
Ali você está criando um novo model. Você só deve criar o model uma única vez, quando criar a tela. Naquele local você deveria só fazer:
modelTable.add(user);

Note que vc também está criando uma nova lista de usuários a cada usuário inserido. E isso também não está certo.

Veja como ta meu Model:

package com.table.models;

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import com.model.User;

public class ModelTable extends AbstractTableModel{

	List<User> lista;
	
	private int COLUMN_NOME = 0;
	private int COLUMN_TEL = 0;
	
	static int contador = 0;
	
	public ModelTable(List<User> list){
		
		this.lista = new ArrayList<User>(list);
		
	}
			
	@Override
	public int getColumnCount() {
		// TODO Auto-generated method stub
		return 2;
	}

	@Override
	public int getRowCount() {
		// TODO Auto-generated method stub
		return this.lista.size();
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
						
		User usuario = this.lista.get(rowIndex); 
				
		if(this.COLUMN_NOME == columnIndex){
			
			return usuario.getNome(); // vai dar nullPointer aqui...
			
		}
		
		if(this.COLUMN_TEL == columnIndex){
			
			return usuario.getTel();
			
		}
		
		return usuario.getTel();
		
	}
	
	public String getColumnName(int columIndex){
		
		if(columIndex == this.COLUMN_NOME){
			return "Usuário";
		}
		
		if (columIndex == this.COLUMN_TEL){
			return "Telefone";   
		}
				      
        return "Telefone";
	}
	
	public void add(User usuario) {   

		lista.add(usuario);   
		
		this.fireTableRowsInserted(lista.size()-1, lista.size()-1);   
		
	}  

}

Se eu criar meu model na inicializaçao do JTable vai dar nullPointer pois tenho que passar um List<User> pro construtor e no método getValueAt vai dar nullPointer.

E a ideia de um novo list seria pra armazenar um unico user pra preencher uma determinada linha...

ViniGodoy

Então, vc pode passar um List vazio, para ter um JTable vazio.
Ou você passa um List carregado do banco. Isso depende do que você quer exibir.

Mas o model vc cria uma vez só. E depois, só adiciona, retira ou modifica coisas dentro dele.

evertonsilvagomesjav

ViniGodoy:
Então, vc pode passar um List vazio, para ter um JTable vazio.
Ou você passa um List carregado do banco. Isso depende do que você quer exibir.

Mas o model vc cria uma vez só. E depois, só adiciona, retira ou modifica coisas dentro dele.

Entao devo modificar meu construtor e posso deixar no default? Com isso meu metodo getValueAt() nao seria mais usado correto? E adicionaria apartir do metodo add()…

ViniGodoy

Isso. Pode criar um construtor default que crie a lista em branco, eu geralmente faço isso também.

Aliás, com o seu TableModel próprio, a idéia é nunca mais usar os métodos getValueAt e setValueAt.
Deixa esses métodos para o JTable usar.

Para você crie métodos como

public User get(int row) { lista.get(row); }

Que te retorne um usuário inteiro. Ou método como add e remove que também aceitem como um usuário como parâmetro. E é isso que vai deixar o código da sua interface gráfica ridiculamente mais simples do que se você usasse o Default.

evertonsilvagomesjav
ViniGodoy:
Isso. Pode criar um construtor default que crie a lista em branco, eu geralmente faço isso também.

Aliás, com o seu TableModel próprio, a idéia é nunca mais usar os métodos getValueAt e setValueAt.
Deixa esses métodos para o JTable usar.

Para você crie métodos como

public User get(int row) {
    lista.get(row);
}

Que te retorne um usuário inteiro. Ou método como add e remove que também aceitem como um usuário como parâmetro. E é isso que vai deixar o código da sua interface gráfica ridiculamente mais simples do que se você usasse o Default.

Se eu nao vou mais usar um list no construtor Vini, como vou fazer pra add nas linhas do Table? Os dois exemplos que vc me passou tanto do add quanto do get estao usando um list pra adicionar porém usando um construtor Default no meu model como vou fazer pra add agora? Sendo que JTable vai procurar getValueAt e o mesmo estara retornando null.

package com.table.models;

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import com.model.User;

public class ModelTable extends AbstractTableModel{

	List<User> lista = new ArrayList(); // NAO TENHO MAIS ESTA LISTA...
	
	private int COLUMN_NOME = 0;
	private int COLUMN_TEL = 0;
				
	@Override
	public int getColumnCount() {
		// TODO Auto-generated method stub
		return 2;
	}

	@Override
	public int getRowCount() {
		// TODO Auto-generated method stub
		return 2;
	}

	
	public String getColumnName(int columIndex){
		
		if(columIndex == this.COLUMN_NOME){
			return "Usuário";
		}
		
		if (columIndex == this.COLUMN_TEL){
			return "Telefone";   
		}
				      
        return "Telefone";
	}
	
	public void add(User usuario) {   

		lista.add(usuario);   
		
		this.fireTableRowsInserted(lista.size()-1, lista.size()-1);   
		
	}

	@Override
	public Object getValueAt(int arg0, int arg1) {
		// TODO Auto-generated method stub
		return null;
	}  

}
Onde crio o table com o model
private JTable getTable(){
    	
    	if(this.table == null){
    	
    		this.table = new JTable();
    	
    		this.model = new ModelTable();
    		
    		table.setModel(model);
    		
    		table.setVisible(true);
    		
    		
    	}
    	
    	return this.table;
    	
    }

Onde chamo o add...

@Override
	public void actionPerformed(ActionEvent e) {
	
		if(e.getSource() == this.buttonCadastrar){
			
			if(!this.text.getText().isEmpty()){
			
				User user = new User();
				
				//List<User> list = new ArrayList<User>();
				
				user.setNome(this.text.getText());
				user.setTel(this.textTel.getText());
				
				//list.add(user);
										
				JOptionPane.showMessageDialog(null,"Cadastro concluido com sucesso:\n" +
										  	  this.text.getText() +" " +this.textTel.getText());
				
						
				
				this.model.add(user);

A duvida maior, é como vou adicionar os dados porque eu entendi que o proprio JTable chama o getValueAt pra adicionar os dados nas linhas, porém ele agora esta retornando null mas mesmo assim JTable o vai chamar pois o metodo esta implementado na minha class, como vou fazer pra add os dados agora com getValueAt retornando null.

ViniGodoy

Não cara, vc não entendeu. Volta a implementação do getValueAt como tava antes que tava certa!

O que eu disse é o seguinte. Você, na sua tela, não vai chamar diretamente o getValueAt nem o setValueAt. Ou seja, no seu botão, jamais haverá algo como:

txtNome.setText(model.getValueAt(0, linha));

E sim algo como:

User user = model.get(linha); txtNome.setText(user.getNome());

Mas o JTable vai, internamente, chamar esses métodos. Ou seja, o setValueAt e o getValueAt são métodos chamados pelo JTable, não por você. De qualquer forma, você deve fornecer uma implementação para eles, como você já estava fazendo.

Então, mantém o getValueAt como estava, e usa o addUser, que deve funcionar.

A lógica toda do processo é essa aqui:

  1. Você vai chamar o model.add(usuario);
  2. Esse método adiciona um usuário na lista, e dispara o evento de que a última linha da tabela foi adicionada;
  3. Ao ouvir esse evento, o JTable vai chamar o getValueAt, para pedir os valores dessa linha;
  4. Com os valores em mãos, a linha será desenhada.
ViniGodoy
O model, depois de pronto, deve ficar assim, coloquei comentários nos locais que corrigi e modifiquei:
package com.table.models;

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import com.model.User;

public class ModelTable extends AbstractTableModel{

    //Nessa lista você grava seus usuários
	List<User> lista; 
	
	private int COLUMN_NOME = 0;
	//O telefone fica na coluna 1
	private int COLUMN_TEL = 1;
				
	public ModelTable(List<User> usuarios)
	{
		lista = new ArrayList<User>(usuarios);
	}
	
	public ModelTable() 
	{
		this(new ArrayList<User>());
	}
	
	@Override
	public int getColumnCount() {
		return 2; //Ok, são duas colunas
	}

	@Override
	public int getRowCount() {
		return lista.size(); //Existirá uma linha na tabela para cada usuário da lista
	}

	
	public String getColumnName(int columIndex){		
		if(columIndex == this.COLUMN_NOME){
			return "Usuário";
		}
		
		if (columIndex == this.COLUMN_TEL){
			return "Telefone";   
		}
				      
        return "Telefone";
	}
	
	public void add(User usuario) {   
	    //Adicionamos um usuário na lista
		lista.add(usuario);   		
		//Avisamos o JTable que ele deve repintar a última linha
		this.fireTableRowsInserted(lista.size()-1, lista.size()-1);   
		
	}

	@Override
	public Object getValueAt(int arg0, int arg1) {
	    //Aqui informamos para o JTable que dado está em cada linha/coluna da tabela.		
        User usuario = this.lista.get(rowIndex);   
                   
         if(this.COLUMN_NOME == columnIndex){  
             return usuario.getNome(); // vai dar nullPointer aqui...  
         }  
           
         if(this.COLUMN_TEL == columnIndex){  
             return usuario.getTel();  
         }  
           
         return usuario.getTel();  	
	}  
}
evertonsilvagomesjav

Editando aqui pq nao vi vc respondendo acima…

Funcionou perfeitamente aqui…Agora Vini o que nao to entendendo é o seguinte, JTable chama getValueAt na hora que eu seto o model certo? Se sim pq nao ta dando nullPointer pois a lista esta vazia…Quando for executado o metodo getValueAt ainda nao usei o metodo add(), portanto era pra dar nullPointerException n? E eu tb achava q a inserção de dados no Table quem fazia era getValueAt automaticamente…

ViniGodoy

A lista está vazia, mas está inicializada (foi inicializada no construtor). Ela não está nula.

O getRowCount() irá retornar 0. E o método getValueAt não será chamado.

O setValueAt só vai ser chamado automaticamente se um usuário alterar um campo já exibido na tabela. Aí a tabela chama esse método para avisar o model que isso aconteceu. Logo depois de chamar o setValueAt, ela chama novamente o getValueAt para pintar o valor alterado.

Isso te dá a possibilidade de cancelar uma alteração dentro da setValueAt.

evertonsilvagomesjav

ViniGodoy:
A lista está vazia, mas está inicializada (foi inicializada no construtor). Ela não está nula.

O getRowCount() irá retornar 0. E o método getValueAt não será chamado.

O setValueAt só vai ser chamado automaticamente se um usuário alterar um campo já exibido na tabela. Aí a tabela chama esse método para avisar o model que isso aconteceu. Logo depois de chamar o setValueAt, ela chama novamente o getValueAt para pintar o valor alterado.

Isso te dá a possibilidade de cancelar uma alteração dentro da setValueAt.

Entao o getValueAt so é chamado se exisitir alguma linha no Table?

Os parametros passados no metodo this.fireTableRowsInserted(lista.size()-1, lista.size()-1); indicam o que especificadamente?

ViniGodoy

Você alterou a sua lista, certo? Então vc precisa avisar ao JTable que a lista foi alterada, para que ela pinte a nova linha.

Aqueles parâmetros indicam os índices da primeira e última linhas adicionadas. No caso, como foi só uma linha no final, ambos os índices são iguais ao índice do último elemento da lista.

evertonsilvagomesjav

ViniGodoy:
Você alterou a sua lista, certo? Então vc precisa avisar ao JTable que a lista foi alterada, para que ela pinte a nova linha.

Aqueles parâmetros indicam os índices da primeira e última linhas adicionadas. No caso, como foi só uma linha no final, ambos os índices são iguais ao índice do último elemento da lista.

Significa então q sempre q executado o aplicativo se for alterado algo no estado do meu model o proprio Table verifica e faz as alterações, isso com base no getValueAt.

ViniGodoy

Isso. Ele verifica pq esse “fire” avisa o JTable que alguma coisa mudou. E o que.

Aí o JTable chama o getValueAt para aplicar as mudanças.

evertonsilvagomesjav

ViniGodoy:
Isso. Ele verifica pq esse “fire” avisa o JTable que alguma coisa mudou. E o que.

Aí o JTable chama o getValueAt para aplicar as mudanças.

Pôo Vini, muito obrigado mais uma vez pelos posts e pela paciencia, em fim entendi rsrsrs.

ViniGodoy

Se a idéia é não usar o DefaultTableModel, a minha paciência é virtualmente infinita…

evertonsilvagomesjav

kkkkk bom saber disso, além do mais eu fugi do DefaultTableModel por sua causa kkk.

ViniGodoy

Mas vai dizer que não é melhor fazer:

model.add(usuario)

Do que:

model.addRow(new Object[] {usuario.getNome(), usuario.getTelefone()});

Fora que, se vc trocar a ordem das colunas, ou se uma coluna nova surgir, vc não precisará alterar nada além do model…

evertonsilvagomesjav

ViniGodoy:
Mas vai dizer que não é melhor fazer:

model.add(usuario)

Do que:

model.addRow(new Object[] {usuario.getNome(), usuario.getTelefone()});

Fora que, se vc trocar a ordem das colunas, ou se uma coluna nova surgir, vc não precisará alterar nada além do model…

kkkkkk Graças á Deus, e ao seu movimento de extinçao do DefaultTableModel, não cheguei á usa-lo muito :D.

Criado 28 de abril de 2010
Ultima resposta 29 de abr. de 2010
Respostas 23
Participantes 2