Implementação da Classe AbstractTableModel

2 respostas
marcos3

Pessoal implementei a classe AbstractTableModel e até aqui tudo bem, porém deixei as colunas como sendo editáveis, o problema é quando o usuário dá um clique duplo sobre determinada coluna ela entra em modo de edição, porém quando a coluna perde o "foco" seu valor é copiado para as demais colunas.

Como é a primeira vez que implemento esta classe acredito que deve estar faltando algum método a ser implementado. Vou postar minha classe abaixo e peço que os colegas com mais experiência me auxiliem para encontrar o problema.

public class ContatosTableModel extends AbstractTableModel{
    //definindo constantes para tratar colunas
    private final int COL_NOME = 0;
    private final int COL_IDADE = 1;    
    private final int COL_CID = 2;
    
    private String[] colunas = new String[]{"Nome","Idade","Cidade"};//define nome das colunas    
    private ArrayList<Contato> contatos;
    
    public ContatosTableModel(){
        contatos = new ArrayList<Contato>();
    }
    
    public ContatosTableModel(ArrayList lista){
        this();
        contatos.addAll(lista);
    }

    @Override
    public int getRowCount() {
        return contatos.size();//cada contato será uma linha
    }

    @Override
    public int getColumnCount() {
        return colunas.length;//retorna a quantidade de colunas que serão exibidas
    }
    
    @Override
    public String getColumnName(int column){
        return colunas[column];//retorna nome da coluna
    }
    
    @Override
    public Class getColumnClass(int columnIndex){
        switch(columnIndex){
            case COL_NOME: return String.class;
            case COL_IDADE: return Integer.class;
            case COL_CID: return String.class;
            default: return String.class;
        }
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Contato c = contatos.get(rowIndex);//pega o contato da linha
        
        //verifica qual valor será retornado
        switch(columnIndex){
            case COL_NOME: return c.getNome();
            case COL_IDADE: return c.getIdade();
            case COL_CID: return c.getCidade();
            default: return "";
        }
    }
    
    @Override
    public void setValueAt(Object aValue,int rowIndex, int columnIndex){
        Contato c = contatos.get(rowIndex);//pega o contato da linha
        
        switch(columnIndex){
            case COL_NOME: c.setNome(aValue.toString());
            case COL_IDADE: c.setIdade(aValue.toString());
            case COL_CID: c.setCidade(aValue.toString());
        }
        
        fireTableDataChanged();//avisa que os dados mudaram
    }
    
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
        return true;//todas as celulas vão ser editáveis
    }
    
    //adicionando meus métodos para manipulação da interface
    
    public void Inserir(Contato c){
        contatos.add(c);
        fireTableDataChanged();        
    }
    
    public void Excluir(Contato c){
        contatos.remove(c);
        fireTableDataChanged();
    }
    
    public void Excluir(int pos){
        contatos.remove(pos);
        fireTableDataChanged();
    }
    
    public Contato getContato(int pos){
        if(pos<0 || pos >= contatos.size()){
            return null;
        }
        return (Contato) contatos.get(pos);
    }
    
}

2 Respostas

marcos3

Pessoal não sei se era apenas isso mas alterei o bloco switch-case por if-else if no método setValueAt e dessa forma o problema párou.

Ficou assim:

@Override
    public void setValueAt(Object aValue,int rowIndex, int columnIndex){
        Contato c = contatos.get(rowIndex);//pega o contato da linha
       
        if(columnIndex == COL_NOME)
            c.setNome(aValue.toString());
        else if(columnIndex == COL_IDADE)
            c.setIdade(aValue.toString());
        else if(columnIndex == COL_CID)
            c.setCidade(aValue.toString());
        
        
        fireTableDataChanged();//avisa que os dados mudaram
    }

Na verdade faltou colocar break, ou seja, pode ficar assim também:

@Override
    public void setValueAt(Object aValue,int rowIndex, int columnIndex){
        Contato c = contatos.get(rowIndex);//pega o contato da linha
        
        switch(columnIndex){
            case COL_NOME: {
                c.setNome(aValue.toString());
                break;
            }
            case COL_IDADE: {
                c.setIdade(aValue.toString());
                break;
            }
            case COL_CID: {
                c.setCidade(aValue.toString());
                break;
            }
        }
        
        fireTableDataChanged();//avisa que os dados mudaram
    }
ViniGodoy

Era mesmo a falta do break. Isso fez falltrough.

Outra coisa, não é necessário, e nem desejável, o fireTableDataChanged dentro do método setValueAt.

Além disso, nos outros métodos, procure trocar o fireTableDataChanged por eventos mais específicos (como FireTableRowsInserted e fireTableRowsDeleted). Avisar o JTable que tudo mudou além de ineficiente vai te dar um comportamento indesejável com a scrollbar. Sem falar que parece coisa de programador preguiçoso.

Criado 10 de setembro de 2014
Ultima resposta 11 de set. de 2014
Respostas 2
Participantes 2