Problema TableModel

17 respostas
Robertdm

Pessoal, estou com um problema em uma jTable minha, pois quando digito um valor em qualquer célula, após trocar de célula o valor não permanece…Eu uso um TableModel que eu criei.

Se alguém souber de algum detalhe que possa estar gerando isso, por favor me ajude.

Obrigado pela atenção e ico no aguardo.

17 Respostas

ViniGodoy

Como está seu método setValueAt do seu TableModel?

Robertdm
ViniGodoy

Cara, vou postar o método getValueAt(que vc me ajudou a fazer) e tb o setValueAt para vc ver:

public void setTrimestre(int trimestre) {
        this.trimestre = trimestre;
        //Isso avisa a tabela que os dados mudaram e que ela deve redesenhar-se.
        //O getValueAt será chamado pra pintar o novo conteúdo.
        fireTableDataChanged();
    }

    public Object getValueAt(int row, int column) {
        //Verifica qual o trimestre pra saber quals valor devolver
        AlunoSaida aluno = alunosSaida.get(row);        
        TrimestreSaida trimestreSaida = aluno.getTrimestre(trimestre);
        System.err.println(trimestreSaida.getAvaliacao1());
            //Retorna os valores do aluno
            if (column == COL_ALUNO)
                return aluno.getNome();
            else if (column == COL_AVAL1)
                return trimestreSaida.getAvaliacao1();
            else if (column == COL_AVAL2)
                return trimestreSaida.getAvaliacao2();
            else if (column == COL_AVAL3)
                return trimestreSaida.getAvaliacao3();
            else if (column == COL_AVAL4)
                return trimestreSaida.getAvaliacao4();
            else if (column == COL_AVAL5)
                return trimestreSaida.getAvaliacao5();
            else if (column == COL_MEDIA)
                return trimestreSaida.getMedia();
            else if (column == COL_FALTA)
                return trimestreSaida.getFaltas();
            else if (column == COL_RECUPERACAO)
                return trimestreSaida.getRecuperacao();
            return "";
    }
   
    public void setValueAt(Object aValue, int row, int column, String trimestre) {
        //Pega a aula da linha row.
        AlunoSaida aluno = alunosSaida.get(row);

        //Verifica qual valor vai ser alterado
        if (("1º Trimestre").equals(trimestre)) {
             //Verifica qual valor deve ser retornado
            if (column == COL_ALUNO)
                aluno.setNome(aValue.toString());
            else if (column == COL_AVAL1)
                aluno.getTrimestre1().setAvaliacao1(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL2)
                aluno.getTrimestre1().setAvaliacao2(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL3)
                aluno.getTrimestre1().setAvaliacao3(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL4)
                aluno.getTrimestre1().setAvaliacao4(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL5)
                aluno.getTrimestre1().setAvaliacao5(Float.parseFloat((String)aValue));
            else if (column == COL_MEDIA)
                aluno.getTrimestre1().setMedia(Float.parseFloat((String)aValue));
            else if (column == COL_FALTA)
                aluno.getTrimestre1().setFaltas(Integer.parseInt((String)aValue));
            else if (column == COL_RECUPERACAO)
                aluno.getTrimestre1().setRecuperacao(Float.parseFloat((String)aValue));
        }

        if (("2º Trimestre").equals(trimestre)) {
             //Verifica qual valor deve ser retornado
            if (column == COL_ALUNO)
                aluno.setNome(aValue.toString());
            else if (column == COL_AVAL1)
                aluno.getTrimestre2().setAvaliacao1(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL2)
                aluno.getTrimestre2().setAvaliacao2(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL3)
                aluno.getTrimestre2().setAvaliacao3(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL4)
                aluno.getTrimestre2().setAvaliacao4(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL5)
                aluno.getTrimestre2().setAvaliacao5(Float.parseFloat((String)aValue));
            else if (column == COL_MEDIA)
                aluno.getTrimestre2().setMedia(Float.parseFloat((String)aValue));
            else if (column == COL_FALTA)
                aluno.getTrimestre2().setFaltas(Integer.parseInt((String)aValue));
            else if (column == COL_RECUPERACAO)
                aluno.getTrimestre2().setRecuperacao(Float.parseFloat((String)aValue));
        }

        if (("3º Trimestre").equals(trimestre)) {
             //Verifica qual valor deve ser retornado
            if (column == COL_ALUNO)
                aluno.setNome(aValue.toString());
            else if (column == COL_AVAL1)
                aluno.getTrimestre3().setAvaliacao1(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL2)
                aluno.getTrimestre3().setAvaliacao2(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL3)
                aluno.getTrimestre3().setAvaliacao3(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL4)
                aluno.getTrimestre3().setAvaliacao4(Float.parseFloat((String)aValue));
            else if (column == COL_AVAL5)
                aluno.getTrimestre3().setAvaliacao5(Float.parseFloat((String)aValue));
            else if (column == COL_MEDIA)
                aluno.getTrimestre3().setMedia(Float.parseFloat((String)aValue));
            else if (column == COL_FALTA)
                aluno.getTrimestre3().setFaltas(Integer.parseInt((String)aValue));
            else if (column == COL_RECUPERACAO)
                aluno.getTrimestre3().setRecuperacao(Float.parseFloat((String)aValue));
        }

        fireTableDataChanged();
    }

Fico no aguardo,

Obrigado

ViniGodoy

O setValueAt é um método especial, que vem do AbstractTableModel. Você deve sobrescreve-lo. Não pode incluir parâmetros nele. Quando vc incluiu aquela String, transformou em outro método, que a JTable não chamará.

Por isso, em métodos sobrescritos (como getValueAt e setValueAt) é bom você escrever @Override antes do método.

Seu setValueAt vai ficar muito parecido com seu getValueAt:

@Override
public void setValueAt(Object aValue, int row, int column) {
   //Verifica qual o trimestre pra saber quals valor devolver
   AlunoSaida aluno = alunosSaida.get(row);        
   TrimestreSaida trimestreSaida = aluno.getTrimestre(trimestre);

   try {
      //Verifica qual valor deve ser retornado
      if (column == COL_ALUNO)
         aluno.setNome(aValue.toString());
      else if (column == COL_AVAL1)
         trimestreSaida.setAvaliacao1(Float.parseFloat((String)aValue));
      else if (column == COL_AVAL2)
         trimestreSaida.setAvaliacao2(Float.parseFloat((String)aValue));
      else if (column == COL_AVAL3)
         trimestreSaida.setAvaliacao3(Float.parseFloat((String)aValue));
      else if (column == COL_AVAL4)
         trimestreSaida.setAvaliacao4(Float.parseFloat((String)aValue));
      else if (column == COL_AVAL5)
         trimestreSaida.setAvaliacao5(Float.parseFloat((String)aValue));
      else if (column == COL_MEDIA)
         trimestreSaida.setMedia(Float.parseFloat((String)aValue));
      else if (column == COL_FALTA)
         trimestreSaida.setFaltas(Integer.parseInt((String)aValue));
      else if (column == COL_RECUPERACAO)
         trimestreSaida.setRecuperacao(Float.parseFloat((String)aValue));
   } catch (NumberFormatException e) {
      //Se informou um float errado, ignora a modificação e volta ao valor antigo.
   }
}

Como foi o JTable que chamou o setValueAt, ele já sabe que precisará repintar a célula, portanto, não é necessário disparar eventos de DataChanged. Só dispare eventos aqui caso alguma outra coluna, além da que ele editou, seja alterada automaticamente no processo (se você tiver uma coluna calculada, por exemplo).

Robertdm

Entendi cara…Vou fazer aqui e ver como fica.

Já que tocou no assunto de uma coluna ser alterada automaticamente, na verdade nessa jTable não tenho isso, mas em outra jTable terei inúmeras colunas que preciso que sejam alteradas quando os valores dessa jTable deste post forem alterados.

Por exemplo, nesta jTable do post tenho a coluna COL_MEDIA (a média das avaliações) e queria que em uma coluna de outra jTable recebe-se esse valor quando o mesmo fosse preenchido, logo acredito que precise dar uma tipo de refresh nesta coluna da outra jTable que precisa se atualizar certo?

Como faço isso?

Obrigado.

ViniGodoy

Mas você vai exibir as duas JTables ao mesmo tempo?

Robertdm

Sim…na verdade assim, tenho uma tela que tem 4 abas sendo que em cada uma destas abas tem uma jTable. Na aba “Notas” tenho uma coluna chamada média onde será inserido manualmente a média de cada aluno, sendo que dependendo do valor do combo trimestre selecionado a tabela altera os valores. Na outra aba chamada “Quadro Geral” tenha uma tabela com as médias de cada trimestre. Eu preciso que quando a média da tabela da aba “Notas” seja preenchida, o valor da coluna media (correspondente ao trimestre selecionado) da tabela da aba “Quadro Geral” seja preenchida automaticamente, sendo que se for clicado na aba “Quadro Geral” o valor já tenha sido atualizado naquela coluna entende?

Espero ter conseguido explicar direitinho.

Fico no aguardo

ViniGodoy

Sim. Você fez isso por passagem de parâmetro.

Outra forma é comunicar pelo banco. Numa aba vc salva, na outra vc recupera. E não deixa seu usuário trocar de aba sem salvar ou cancelar a ação.

Robertdm
ViniGodoy

Cara, precisava de um auxilio no seguinte. Estou com problemas ao construir a jTable chamando o construtor dela que recebe uma lista. Por exemplo, tenho minha seguinte TableModel:

public class AulasTableModel extends AbstractTableModel{

    private static final int COL_DATA = 0;
    private static final int COL_DESCRICAO = 1;

    private List<AulaSaida> aulasSaida;

    //Construtor default que apenas cria uma lista vazia de aulasSaida
    public AulasTableModel() {
        aulasSaida = new ArrayList<AulaSaida>();
        fireTableDataChanged();
    }

    //Esse é um construtor, que recebe a nossa lista de aulas
    public AulasTableModel(List<AulaSaida> aulasSaida) {
        this();
        this.aulasSaida.addAll(aulasSaida);
        fireTableDataChanged();
    }

    public void addRow(AulaSaida aulaSaidaNova) {
        //Adiciona uma linha na tabela        
        aulasSaida.add(aulaSaidaNova);
        fireTableDataChanged();        
    }

    public int getRowCount() {
        //Quantas linhas tem sua tabela? Uma para cada item da lista.
        return aulasSaida.size();
    }

    public int getColumnCount() {
        //Quantas colunas tem a tabela? Nesse exemplo, só 2.
        return 2;
    }

    public String getColumnName(int column) {
        //Qual é o nome das nossas colunas?
        if (column == COL_DATA)
            return "Data";
        if (column == COL_DESCRICAO)
            return "Descriçâo";
        return ""; //Nunca deve ocorrer
    }

    public Object getValueAt(int row, int column) {
        //Pega a aula da linha row.
        AulaSaida aula = aulasSaida.get(row);

        //Verifica qual valor deve ser retornado
        if (column == COL_DATA)
            return aula.getData();
        else if (column == COL_DESCRICAO)
            return aula.getDescricao();
        return ""; //Nunca deve ocorrer
    }

    public void setValueAt(Object aValue, int row, int column) {
        //Pega a aula da linha row.
        AulaSaida aula = aulasSaida.get(row);

        //Verifica qual valor vai ser alterado
        if (column == COL_DATA)
            aula.setData(aValue.toString());
        else if (column == COL_DESCRICAO)
            aula.setDescricao(aValue.toString());

        fireTableDataChanged();
    }

    public boolean isCellEditable(int row, int column) {
        //Indicamos se a célula da row e da column é editável.Nossa tabela toda é.
        return true;
    }

    public AulaSaida get(int row) {
        //Já que esse tableModel é de AulasSaida, vamos fazer um get que retorne uma aulaSaida inteira.
        //Isso elimina a necessidade de chamar o getValueAt() nas telas.
        return aulasSaida.get(row);
    }

}

Sendo que na minha classe "Principal.java" eu faço o seguinte:

jTableAulas = new JTable();
AulasTableModel modelAulas = new AulasTableModel(aulas);
jTableAulas.setModel(modelAulas);

Considerando que "aulas" é uma lista.

Não ocorre nenhuma exceção, mas a jTableNotas não é montada e tb o botão "adicionar linha" (insere uma nova linha na tabela chamando o construtor default) não funciona, é como se ficasse tudo travado.

Agradeço a atenção e fico no aguardo.

ViniGodoy

Nossa, você gosta do fireTableDataChanged(), hein? Não adianta disparar isso no construtor, pois o model nem estará associado ao JTable ainda:

O problema é que no seu construtor que recebe a lista, você chama o addAll sem dar new na lista.

Sugestão, deixe seus construtores assim:
//Construtor default que apenas cria uma lista vazia de aulasSaida  
public AulasTableModel() {  
   this(new ArrayList&lt;AulaSaida&gt;());
}  

//Esse é um construtor, que recebe a nossa lista de aulas  
public AulasTableModel(List&lt;AulaSaida&gt; aulasSaida) {  
   this.aulasSaida = new ArrayList&lt;AulaSaida&gt;(aulasSaida);
}
Já aproveitando, mude seu addRow para:
public void addRow(AulaSaida aulaSaidaNova) {  
   //Adiciona uma linha na tabela          
   aulasSaida.add(aulaSaidaNova);  
   fireTableTableRowsInserted(aulasSaida.size() -1, aulasSaida.size() -1);
}

E tire o fireTableDataChanged do seu setValueAt. Como já te expliquei, ele é desnecessário.

Evite ao máximo chamar fireTableDataChanged. Ele é terrívelmente ineficiente, pois manda a sua JTable redesenhar inteira. No lugar, chame os eventos mais específicos: fireTableRowsDeleted, fireTableRowsInserted e fireTableRowsUpdated

Robertdm
ViniGodoy

Cara, aí embaixo estão as modificações que fiz e tb tirei o fireTableDataChanged do setValueAt. Mas mesmo assim não funciona, pois continua não mostrando nada na jTable e o botão de adicionar linhas não consegue fazer nada, ou seja, continua como antes.

public AulasTableModel() {
        this(new ArrayList<AulaSaida>());
    }

    //Esse é um construtor, que recebe a nossa lista de aulas
    public AulasTableModel(List<AulaSaida> aulasSaida) {       
        this.aulasSaida = new ArrayList<AulaSaida>(aulasSaida);
    }

    public void addRow(AulaSaida aulaSaidaNova) {
        //Adiciona uma linha na tabela        
        aulasSaida.add(aulaSaidaNova);
        fireTableRowsInserted(aulasSaida.size() -1, aulasSaida.size() -1);
    }

Tentei inclusive colocar valores ficos no getValueAt para ver se o problema era nos valores da lista passada no construtor, mas não surtiu nenhum efeito.

Alguma dica?

Obrigado.

ViniGodoy

Pode postar o código todo da interface gráfica onde você cria a tabela? O model aparentemente está certo.

Robertdm

Coloquei em anexo a pasta que tem a classe onde tem toda parte gráfica.

Só pra esclarecer, eu usei o NetBeans pra montar a parte gráfica arrastando os componentes e tal, então não sei direito onde e como ele az, apenas acesso via propriedades opu personalização do código…

Abstraia alguma redundância ou amadorismo de código, por favor.

Fico no aguardo.

Obrigado.

ViniGodoy

No método jButtonCarregaActionPerformed(java.awt.event.ActionEvent evt), simplesmente retire essa linha:

Isso está criando uma nova JTable. Você deve só atualizar a JTable que já está na tela.

Para isso, é só substituir o model na variável jTableAulas que já está declarada.

ViniGodoy

Se eu fosse ligar para essas coisas, eu não daria aula. hehehehe

Outra coisa, seu código está com o TableModel correto. Só isso já deixa ele muito, muito, muito, mais profissional que qualquer “experiente” que insiste no Default por aqui (e pior, tem vários).

Robertdm

Perfeito cara!!!

Funcionou direitinho.

Só queria entender uma coisa, no método

O que exatamente significa os parâmetros para o método e se puder me explicar como ele “pensa ou faz”.

Li na documentação mas não entendi direito.

Muito obrigado pela ajuda.

Grande abraço.

ViniGodoy

Ele avisa a tabela que aquelas linhas foram inseridas.
O parâmetro é o índice da primeira linha inserida, o segundo é o índice da última.

Como naquele método você inseriu uma linha só, no final, o índice dessa linha é o tamanho do seu list -1.

Robertdm

Entendi…

Muito obrigado por toda ajuda e principalmente pela paciência aí cara.

Vc sabe se existe algum post ou tutorial sobre formtações dos campos da jTable bem como validação do valores permitidos para inserção?

Grande abraço.

Criado 26 de outubro de 2010
Ultima resposta 27 de out. de 2010
Respostas 17
Participantes 2