Edição de Célula da JTable

4 respostas
A

Bom dia a todos,

Estou com um problema de edição de célula na minha tabela e gostaria de ajuda.
O problema é o seguinte, criei um model para a tabela e neste model tem as colunas que podem ser editadas, porém, quando edito a celula e saio da mesma o valor desaparece. Como posso fazer para o valor persistir na celula que foi digitada?

Segue abaixo o codigo usado:

Código do modelo criado:
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.table.*;

/**
 *
 * 
 * @author Visitante
 */
public class TabelaVendaProduto extends AbstractTableModel{  
  
    private Object[] objeto;
    private List<Object[]> listaObjetos;
    
    private String[] colunas = new String[]{"Código", "Produto", "Quantidade", "Desconto", "Preço Unitário", "Preço Total"};  
  
    public TabelaVendaProduto(){  
        if (listaObjetos == null)
            listaObjetos = new ArrayList<Object[]>();
        objeto = new Object[]{"", "", "", "", "", ""};
        listaObjetos.add(objeto);
    }  
  
    public TabelaVendaProduto(List<Object[]> listaObject){  
        listaObjetos = new ArrayList<Object[]>(listaObject);  
    }  
  
    //Carrega objeto na lista
    public void setObjeto(Object[] obj){
        objeto = obj;
        listaObjetos.add(objeto);
    }
	
    //Retorna um objeto da lista da tabela
    public Object[] getObjeto(int indiceLinha){
        return listaObjetos.get(indiceLinha);
    }
    
    //Retorna a quantidade de colunas
    @Override  
    public int getColumnCount(){  
        return colunas.length;  
    }  
  
    //Retorna a quantidade de linhas
    @Override  
    public int getRowCount(){  
        return listaObjetos.size();  
    }  
  
    //Retorna o nome de uma coluna específica
    @Override  
    public String getColumnName(int coluna){  
        return colunas[coluna];  
    }  
  
    //Define o tipo de retorno
    @Override  
    public Class<?> getColumnClass(int columnIndex){  
  
        switch (columnIndex){  
            case 0:  
                return String.class;  
            case 1:  
                return String.class;  
            case 2:  
                return String.class;  
            case 3:  
                return String.class;  
            case 4:  
                return String.class;  
            case 5:  
                return String.class; 
            default:  
                throw new IndexOutOfBoundsException("ColumnIndex out of bounds");  
        }  
    }  
  
    @Override  
    public Object getValueAt(int linha, int coluna){  
        
        switch (coluna){  
            case 0:  
                return listaObjetos.get(linha)[coluna];
            case 1:  
                return listaObjetos.get(linha)[coluna];
            case 2:  
                return listaObjetos.get(linha)[coluna];
            case 3:  
                return listaObjetos.get(linha)[coluna];
            case 4:  
                return listaObjetos.get(linha)[coluna];
            case 5:  
                return listaObjetos.get(linha)[coluna];
            default:  
                throw new IndexOutOfBoundsException("Column out of bounds");  
        }  
    }  
  
    public void setValutAt(Object dados, int linha, int coluna){
        objeto = listaObjetos.get(linha);
        objeto[coluna] = dados;
        listaObjetos.add(linha, objeto);
        fireTableCellUpdated(linha, coluna);
    }
  
    @Override  
    public boolean isCellEditable(int rowIndex, int columnIndex){  
        if (columnIndex < 2){
            return false;
        } else {
            return true;
        }
    }  

    public void addObjeto (Object[] obj){  
        listaObjetos.add(obj);  
        int ultimoIndice = getRowCount() - 1;  
        fireTableRowsInserted(ultimoIndice, ultimoIndice);  
  
    }  
  
    public void removeObjeto(int indiceLinha){  
        listaObjetos.remove(indiceLinha);  
        fireTableRowsDeleted(indiceLinha, indiceLinha);  
    }  
  
    public void addListaObjeto(List<Object[]> listaObj){  
        limpar();
        int tamanhoAntigo = getRowCount();  
        listaObjetos.addAll(listaObj);  
        fireTableRowsInserted(tamanhoAntigo, getRowCount() -1);  
          
    }  
  
    public void limpar(){  
        listaObjetos.clear();  
        fireTableDataChanged();  
    }  
  
    public boolean isEmpty(){  
        return listaObjetos.isEmpty();  
    }

    
}
Metodo usado na view para construir a tabela:
private void construirTabelaVendaProduto(){
        
        tbVendaProduto.setModel(new TabelaVendaProduto());
        tbVendaProduto.setAutoCreateRowSorter(true);
        tbVendaProduto.setRowHeight(25);
  
        tbVendaProduto.getColumnModel().getColumn(0).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(1).setPreferredWidth(400);
        tbVendaProduto.getColumnModel().getColumn(2).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(3).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(4).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(5).setPreferredWidth(50);
   
    }
    
    private TabelaVendaProduto getModel() {  
        if (modeloVendaProduto == null) {  
            modeloVendaProduto = (TabelaVendaProduto) tbVendaProduto.getModel();  
        }  
        return modeloVendaProduto;  
    }
Metodo para controlar o ENTER na tabela:
private void tbVendaProdutoKeyPressed(java.awt.event.KeyEvent evt) {                                          
        // TODO add your handling code here:
        
        if (evt.getKeyCode() == KeyEvent.VK_ENTER){
            
            int linha = tbVendaProduto.getSelectedRow();
            int coluna = tbVendaProduto.getSelectedColumn();
            
            if (coluna == 0){
                
                JDialog consultarPop = this.criaDialogConsulta(Utils.PRODUTO);
                consultarPop.setVisible(true);

                produtoSelecionado = painelConsulta.getProdutoSelecionado();
                
                vendaProduto = new Object[]{
                    produtoSelecionado.getCodProduto(),
                    produtoSelecionado.getDescricao(),
                    "1",
                    "",
                    produtoSelecionado.getValorVenda(),
                    ""
                };
                
                if (listaVendaProduto == null)
                    listaVendaProduto = new ArrayList<Object[]>();
                
                listaVendaProduto.add(vendaProduto);
                
                ((TabelaVendaProduto)tbVendaProduto.getModel()).addListaObjeto(listaVendaProduto);
                
                tbVendaProduto.setColumnSelectionInterval(coluna + 2, coluna + 2);
                
            } 
                      
            if (coluna == 5){

                if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
                    evt.consume();

                    vendaProduto = new Object[]{"", "", "", "", "", ""};
                    
                    if (tbVendaProduto.getSelectedRow() == tbVendaProduto.getRowCount() - 1){
                        ((TabelaVendaProduto)tbVendaProduto.getModel()).addObjeto(vendaProduto);
                    }

                    tbVendaProduto.setSurrendersFocusOnKeystroke(true);
                    tbVendaProduto.setColumnSelectionInterval(0, 0);
                    tbVendaProduto.setRowSelectionInterval(linha + 1, linha + 1);

                }

            } 

        }
        
        if (evt.getKeyCode() == KeyEvent.VK_DELETE){
            int response = JOptionPane.showConfirmDialog(this, "Tem certeza que deseja excluir este ítem?");
            if (response == JOptionPane.YES_OPTION) {
                int linha = tbVendaProduto.getSelectedRow();
                ((TabelaVendaProduto)tbVendaProduto.getModel()).removeObjeto(linha);
                listaVendaProduto.remove(linha);
                if (((TabelaVendaProduto)tbVendaProduto.getModel()).getRowCount() == 0){
                    vendaProduto = new Object[]{"", "", "", "", "", ""};
                    ((TabelaVendaProduto)tbVendaProduto.getModel()).addObjeto(vendaProduto);
                }
            }
        }
        
        
    }

Utilizo o NetBeans e gostaria de ajuda para resolver esse problema.
Grato.

4 Respostas

Nicolas_Fernandes

Fala, AlanRS!

Bom, vamos começar:

1. Seu método está errado.
public void setValutAt(Object dados, int linha, int coluna){  
        objeto = listaObjetos.get(linha);  
        objeto[coluna] = dados;  
        listaObjetos.add(linha, objeto);  
        fireTableCellUpdated(linha, coluna);  
    }
Mude a assinatura dele para setValueAt e adicione a notação @Override nele. Outra coisa: trabalhe com objetos tipados. Coleção de array de objetos? Larga a mão disso. Faz sua coleção de uma classe específica que, no caso, creio que seja Produto.
public class TabelaVendaProduto extends AbstractTableModel {

    private List<Produto> listaProdutos;
}
É muito mais fácil você trabalhar com uma coleção tipada, já que sua tabela, provavelmente, pertence à classe especificada. Mais uma coisa: a implementação do método. O parâmetro dados é o valor que você digitou; logo, você deve adicioná-lo ao atributo específico.
public void setValueAt(Object dados, int linha, int coluna) {  

        objeto = listaObjetos.get(linha);  

        if (coluna == COLUNAPRODUTO) objeto.setProduto(dados);
        if (coluna == COLUNAQUANTIDADE) objeto.setQuantidade(dados);
        // e assim por diante...
    }

Espero ter ajudado, abraços!

A

E ai Nicolas,

cara era isso mesmo, valeu pela ajuda. Funcionou certinho.

Viu aproveitando o topico, como eu posso fazer para controlar o comportamento do ENTER?
Ex: quando pressionar ENTER ao invés de pular para a celula de baixo, o cursor pular para a celula ao lado?

Tenho mais uma duvida tb…
Como que posso fazer para quando pressionar o ENTER o caret (palito piscante do cursor) pular para a outra celula?

Mais uma vez te agradeço.

Nicolas_Fernandes

AlanRS:
E ai Nicolas,

cara era isso mesmo, valeu pela ajuda. Funcionou certinho.

Viu aproveitando o topico, como eu posso fazer para controlar o comportamento do ENTER?
Ex: quando pressionar ENTER ao invés de pular para a celula de baixo, o cursor pular para a celula ao lado?

Tenho mais uma duvida tb…
Como que posso fazer para quando pressionar o ENTER o caret (palito piscante do cursor) pular para a outra celula?

Mais uma vez te agradeço.


Que bom!

Bom, essa parte de controlar o ENTER na tabela eu vou ficar devendo…
Aliás, até gostaria de saber a resposta!

Quem puder compartilhar conhecimento, por favor!!
Abraços!

A

Opa, novamente obrigado pela atenção Nicolas,

Consegui resolver o problema, não sei se é a melhor solução mas lá vai:

Para controlar a movimentação do enter para a célula da coluna ao lado quando o usuário digita alguma coisa na célula eu usei este evento:

tbVendaProduto.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {
                int col = e.getColumn();
                int linha  = tbVendaProduto.getSelectedRow();
                
                if (col == 2 || col == 3 || col == 4){
                    String quantidade = listaVendaProduto.get(linha)[2].toString();
                    String desconto = listaVendaProduto.get(linha)[3].toString();
                    String vlUnitario = listaVendaProduto.get(linha)[4].toString();
                    
                    listaVendaProduto.get(linha)[5] = calculaValorPorProduto(quantidade, desconto, vlUnitario);
                    ((TabelaVendaProduto)tbVendaProduto.getModel()).addListaObjeto(listaVendaProduto);
                    
                    tbVendaProduto.setSurrendersFocusOnKeystroke(true); 
                    tbVendaProduto.setColumnSelectionInterval(col + 1, col + 1);
                    tbVendaProduto.setRowSelectionInterval(linha, linha);
                }
               
            }
        });

e para controlar a movimentação do enter para a célula da coluna ao lado quando o usuário NÃO digita nada, somente pressiona o enter na tabela eu usei este outro que achei pesquisando na net:

public void tableEnterAction(final JTable tabelaVendaProduto) {   
  
        InputMap im = tabelaVendaProduto.getInputMap(tabelaVendaProduto.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);     
        KeyStroke enter = KeyStroke.getKeyStroke("ENTER");     
        im.put(enter, im.get(KeyStroke.getKeyStroke(KeyEvent.VK_GREATER, 0)));     
        Action enterAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e)   
            {   
               tabelaVendaProduto.setColumnSelectionInterval(tabelaVendaProduto.getSelectedColumn()+1, tabelaVendaProduto.getSelectedColumn()+1); 
            }   
        };   
  
        tabelaVendaProduto.getActionMap().put(im.get(enter), enterAction);   
        
    }

O primeiro coloquei diretamente no metodo construir tabela que passei anteriormente e o segundo coloquei somente a sua chamada no metodo construir tabela:

private void construirTabelaVendaProduto(){
        
        //Metodo para alinhar conteúdo da tabela
        DefaultTableCellRenderer alinha = new DefaultTableCellRenderer() {
            @Override
            public void setValue(Object value) {
                setHorizontalAlignment(JLabel.CENTER);
                super.setValue(value);
            }
        };
        
        tbVendaProduto.setModel(new TabelaVendaProduto());
        tbVendaProduto.setAutoCreateRowSorter(true);
        tbVendaProduto.setRowHeight(25);
        
        tbVendaProduto.getColumnModel().getColumn(0).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(1).setPreferredWidth(400);
        tbVendaProduto.getColumnModel().getColumn(2).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(3).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(4).setPreferredWidth(50);
        tbVendaProduto.getColumnModel().getColumn(5).setPreferredWidth(50);

        TableColumn tcCodigo = tbVendaProduto.getColumnModel().getColumn(0);
        tcCodigo.setCellRenderer(alinha);
        TableColumn tcQuantidade = tbVendaProduto.getColumnModel().getColumn(2);
        tcQuantidade.setCellRenderer(alinha);
        TableColumn tcDesconto = tbVendaProduto.getColumnModel().getColumn(3);
        tcDesconto.setCellRenderer(alinha);
        TableColumn tcPrecoUnit = tbVendaProduto.getColumnModel().getColumn(4);
        tcPrecoUnit.setCellRenderer(alinha);
        TableColumn tcPrecoTotal = tbVendaProduto.getColumnModel().getColumn(5);
        tcPrecoTotal.setCellRenderer(alinha);
        
        tbVendaProduto.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {
                int col = e.getColumn();
                int linha  = tbVendaProduto.getSelectedRow();
                
                if (col == 2 || col == 3 || col == 4){
                    String quantidade = listaVendaProduto.get(linha)[2].toString();
                    String desconto = listaVendaProduto.get(linha)[3].toString();
                    String vlUnitario = listaVendaProduto.get(linha)[4].toString();
                    
                    listaVendaProduto.get(linha)[5] = calculaValorPorProduto(quantidade, desconto, vlUnitario);
                    ((TabelaVendaProduto)tbVendaProduto.getModel()).addListaObjeto(listaVendaProduto);
                    
                    tbVendaProduto.setSurrendersFocusOnKeystroke(true); 
                    tbVendaProduto.setColumnSelectionInterval(col + 1, col + 1);
                    tbVendaProduto.setRowSelectionInterval(linha, linha);
                }
               
            }
        });
        
        tableEnterAction(tbVendaProduto);
        
    }

Se alguém tiver uma solução melhor, favor postar.

Espero poder ajudar alguém com isso como recebi ajuda do Nicolas.

Até.

Criado 28 de setembro de 2011
Ultima resposta 28 de set. de 2011
Respostas 4
Participantes 2