Capturar linha selecionada de uma JTable!

Geralmente para cada classe é um DAO.

Outra coisa, é uma boa usar o PreparedStatement. Ele deixa o código sem concatenação e evita problemas:

[code]public void inserir (Amigo amigo) {
try {
//Fazemos a inserção do amigo no banco
PreparedStatement stmt = bancoAmigo.conn.prepareStatement(
“INSERT INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)”);
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.executeUpdate();

  //Obtemos a chave criada automaticamente
  ResultSet rs = stmt.getGeneratedKeys();
  if (rs.next()) {
     amigo.setCodigo(rs.getInt(1));
  }

} catch (Exception e) {
throw new RuntimeException(e);
}
} [/code]

A vantagem do PreparedStatement são as seguintes:

  1. Permite que você use objetos de data, sem ter que se preocupar com formato do banco de dados. Isso também deixa o código mais portável, já que os formatos de data podem mudar de banco para banco;
  2. Permite que você use Strings, sem ter que se preocupar com caracteres como as aspas simples (considere o que ocorreria no seu código se um usuário inserisse aspas simples no endereço ou no nome);
  3. Evita a falha de segurança de SQL Injection;
  4. Deixa o código mais claro, já que evita aquele monte de concatenação;

Classe AmigoDAO está da seguinte maneira:

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class AmigoDAO {

    Menus.Banco bancoAmigo = new Menus.Banco();

    public List<Amigo> carregar() {
        try {
            List<Amigo> amigos = new ArrayList<Amigo>();
            //Código para carregar os amigos do banco aqui
            PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement("SELECT * FROM Amigos ORDER BY nome");
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                //Criamos um novo amigo
                Amigo amigo = new Amigo();
                amigo.setCodigo(rs.getInt("codigo"));
                amigo.setNome(rs.getString("nome"));
                amigo.setEndereco(rs.getString("endereco"));
                amigo.setBairro(rs.getString("bairro"));
                amigo.setTelefone(rs.getString("Telefone"));
                //Colocamos ele na lista
                amigos.add(amigo);
            }

            //Retornamos a lista de amigos
            return amigos;
        } catch (SQLException e) {

            //Se ocorrer erros, disparamos na forma de uma RuntimeException
            //Isso evitará que tenhamos que ficar tratando erros que raramente ocorrem.
            //E que não podemos fazer muita coisa para nos recuperar é o caso das SQLException.
            throw new RuntimeException(e);
        }
    }

    public void salvar(Amigo amigo) {
        if (amigo.getCodigo() == -1) {
            inserir(amigo); //Faz um INSERT no banco
        } else {
            atualizar(amigo); //Faz um UPDATE no banco.
        }
    }

    public void inserir(Amigo amigo) {
        try {
            //Fazemos a inserção do amigo no banco
            PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement(
            "INSERT INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");
            stmt.setString(1, amigo.getNome());
            stmt.setString(2, amigo.getEndereco());
            stmt.setString(3, amigo.getBairro());
            stmt.setString(4, amigo.getTelefone());
            stmt.executeUpdate();

            //Obtemos a chave criada automaticamente
            ResultSet rs = stmt.getGeneratedKeys();
            if (rs.next()) {
                amigo.setCodigo(rs.getInt(1));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void atualizar(Amigo amigo) {
        try {
            //Fazemos a inserção do amigo no banco
            java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(
                    "UPDATE INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");
            stmt.setString(1, amigo.getNome());
            stmt.setString(2, amigo.getEndereco());
            stmt.setString(3, amigo.getBairro());
            stmt.setString(4, amigo.getTelefone());
            stmt.executeUpdate();

            //Obtemos a chave criada automaticamente
            ResultSet rs = stmt.getGeneratedKeys();
            if (rs.next()) {
                amigo.setCodigo(rs.getInt(1));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Então, qual seria o proximo passo?

Cuidado. O UPDATE não tem a palavra INTO. E você precisa especificar no WHERE sobre qual ID vc está fazendo o UPDATE.

Como no momento do Update a chave é conhecida, não há a necessidade de obter do banco novamente qual chave foi inserida.

Entao, seria + ou menos assim:


public void atualizar(Amigo amigo) {   
        try {   
            //Fazemos a inserção do amigo no banco   
            java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(   
                    "UPDATE Amigos WHERE CODIGO (nome, endereco, bairro, tel) VALUES(?,?,?,?)");   
            stmt.setString(1, amigo.getNome());   
            stmt.setString(2, amigo.getEndereco());   
            stmt.setString(3, amigo.getBairro());   
            stmt.setString(4, amigo.getTelefone());   
            stmt.executeUpdate();   
  
            //Obtemos a chave criada automaticamente   
            ResultSet rs = stmt.getGeneratedKeys();   
            if (rs.next()) {   
                amigo.setCodigo(rs.getInt(1));   
            }   
        } catch (Exception e) {   
            throw new RuntimeException(e);   
        }   
    }   

No caso, a parte do codigo ali seria a variavel, o metodo getCodigo ou o campo no bando de dados?

 java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(     
                     "UPDATE Amigos SET nome=?, endereco=?, bairro=?, tel=? WHERE codigo=?");     
             stmt.setString(1, amigo.getNome());     
             stmt.setString(2, amigo.getEndereco());     
             stmt.setString(3, amigo.getBairro());     
             stmt.setString(4, amigo.getTelefone());     
             stmt.setInt(5, amigo.getCodigo()); //Precisamos informar quem está sendo alterado

Não tente programar por tentativa e erro, aí não funciona mesmo. Procure pela sintaxe do SQL, senão não vai funcionar nunca. Mas minha grande frustração com SQL, e que nunca entendi, é pq nunca fizeram a sintaxe do INSERT e do UPDATE parecidas. Por mim, todas tinham que seguir a do update.

O INSERT deixa o nome dos campos longe dos valores, é dependente de ordem. Nenhum desses problemas ocorre na sintaxe do UPDATE.

Ja não algo assim tão facil de se entender, e so tende a ficar mais dificil.

stmt.setString(5, amigo.getCodigo());

Nessa linha deu erro, mas o codigo nao seria um Integer?

stmt.setInt(5, amigo.getCodigo());

Ops, seria sim. Sorry, me empolguei no copy&paste. hehhee

Entao, minha classe DAO com as devidas correçoes:

import java.sql.ResultSet;   
import java.sql.SQLException;   
import java.util.ArrayList;   
import java.util.List;   
  
public class AmigoDAO {   
  
    Menus.Banco bancoAmigo = new Menus.Banco();   
  
    public List<Amigo> carregar() {   
        try {   
            List<Amigo> amigos = new ArrayList<Amigo>();   
            //Código para carregar os amigos do banco aqui   
            PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement("SELECT * FROM Amigos ORDER BY nome");   
            ResultSet rs = stmt.executeQuery();   
            while (rs.next()) {   
                //Criamos um novo amigo   
                Amigo amigo = new Amigo();   
                amigo.setCodigo(rs.getInt("codigo"));   
                amigo.setNome(rs.getString("nome"));   
                amigo.setEndereco(rs.getString("endereco"));   
                amigo.setBairro(rs.getString("bairro"));   
                amigo.setTelefone(rs.getString("Telefone"));   
                //Colocamos ele na lista   
                amigos.add(amigo);   
            }   
  
            //Retornamos a lista de amigos   
            return amigos;   
        } catch (SQLException e) {   
  
            //Se ocorrer erros, disparamos na forma de uma RuntimeException   
            //Isso evitará que tenhamos que ficar tratando erros que raramente ocorrem.   
            //E que não podemos fazer muita coisa para nos recuperar é o caso das SQLException.   
            throw new RuntimeException(e);   
        }   
    }   
  
    public void salvar(Amigo amigo) {   
        if (amigo.getCodigo() == -1) {   
            inserir(amigo); //Faz um INSERT no banco   
        } else {   
            atualizar(amigo); //Faz um UPDATE no banco.   
        }   
    }   
  
    public void inserir(Amigo amigo) {   
        try {   
            //Fazemos a inserção do amigo no banco   
            PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement(   
            "INSERT INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");   
            stmt.setString(1, amigo.getNome());   
            stmt.setString(2, amigo.getEndereco());   
            stmt.setString(3, amigo.getBairro());   
            stmt.setString(4, amigo.getTelefone());   
            stmt.executeUpdate();   
  
            //Obtemos a chave criada automaticamente   
            ResultSet rs = stmt.getGeneratedKeys();   
            if (rs.next()) {   
                amigo.setCodigo(rs.getInt(1));   
            }   
        } catch (Exception e) {   
            throw new RuntimeException(e);   
        }   
    }   
  
    public void atualizar(Amigo amigo) {   
        try {   
            //Fazemos a inserção do amigo no banco   
            java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(       
                    "UPDATE Amigos SET nome=?, endereco=?, bairro=?, tel=? WHERE codigo=?");       
            stmt.setString(1, amigo.getNome());       
            stmt.setString(2, amigo.getEndereco());       
            stmt.setString(3, amigo.getBairro());       
            stmt.setString(4, amigo.getTelefone());       
            stmt.setInt(5, amigo.getCodigo()); //Precisamos informar quem está sendo alterado
            stmt.executeUpdate();   
  
            //Obtemos a chave criada automaticamente   
            ResultSet rs = stmt.getGeneratedKeys();   
            if (rs.next()) {   
                amigo.setCodigo(rs.getInt(1));   
            }   
        } catch (Exception e) {   
            throw new RuntimeException(e);   
        }   
    }   
}  

Tudo em ordem? Se sim, qual seria o proximo passo?

Bom, o próximo passo é montar o TableModel.
Veja bem, agora vc tem um List<Amigo>, certo? Fica fácil carregar seus amigos do banco e salva-los lá. Chegou a hora de exibi-los.

Dê uma olhada nesses tópicos, que explicam como criar um TableModel:
http://www.guj.com.br/posts/list/149034.java#808003
http://www.guj.com.br/posts/list/132698.java#714736

Deve ser bem fácil adaptar para o seu caso.

Alterei este exemplo:

package Teste;

import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class AmigoTableModel extends AbstractTableModel {
    private static final int COL_CODIGO = 0;
    private static final int COL_NOME = 1;
    private static final int COL_ENDERECO = 2;
    private static final int COL_BAIRRO = 3;
    private static final int COL_TELEFONE = 4;
    private List<Amigo> valores;


    //Esse é um construtor, que recebe a nossa lista de livros
    public TableModel(List<Amigo> valores) {
        this.valores = new ArrayList<Amigo>(valores);
    }

    public int getRowCount() {
        //Quantas linhas tem sua tabela? Uma para cada item da lista.
        return valores.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_CODIGO) {
            return "Codigo";
        }
        if (column == COL_NOME) {
            return "Nome";
        }
        if (column == COL_ENDERECO) {
            return "Endereço";
        }
        if (column == COL_BAIRRO) {
            return "Bairro";
        }
        if (column == COL_TELEFONE) {
            return "Telefone";
        }
        return ""; //Nunca deve ocorrer
    }

    public Object getValueAt(int row, int column) {
        //Precisamos retornar o valor da coluna column e da linha row.
        Amigo titulo = valores.get(row);
        if (column == COL_CODIGO) {
            return titulo.getCodigo();
        } else if (column == COL_NOME) {
            return titulo.getNome().getNome();
        } else if (column == COL_ENDERECO){
            return titulo.getEndereco().getEndereco();
        } else if (column == COL_BAIRRO){
            return titulo.getBairro().getBairro();
        } else if (column == COL_TELEFONE){
            return titulo.getTelefone().getTelefone();
        }
        return ""; //Nunca deve ocorrer
    }

    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
        //Note que vc poderia alterar 2 campos ao invés de um só.
        if (columnIndex == COL_NOME) {
            titulo.setTitulo(aValue.toString());
        } else if (columnIndex == COL_AUTOR) {
            titulo.getAutor().setNome(aValue.toString());
        }
    }

    public Class<?> getColumnClass(int columnIndex) {
        //Qual a classe das nossas colunas? Como estamos exibindo texto, é string.
        return String.class;
    }

    public boolean isCellEditable(int rowIndex, int columnIndex) {
        //Indicamos se a célula da rowIndex e da columnIndex é editável. Nossa tabela toda é.
        return true;
    }
    //Já que esse tableModel é de livros, vamos fazer um get que retorne um livro inteiro.
    //Isso elimina a necessidade de chamar o getValueAt() nas telas.

    public Amigo get(int row) {
        return valores.get(row);
    }
}

E por ai mesmo?

E nessa parte:

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
        //Note que vc poderia alterar 2 campos ao invés de um só.
        if (columnIndex == COL_NOME) {
            titulo.setTitulo(aValue.toString());
        } else if (columnIndex == COL_AUTOR) {
            titulo.getAutor().setNome(aValue.toString());
        }
    }

Aqui e necessario inserir todos os campos desde codigo ate telefone?
E esta variavel titulo, onde ela e declarada/criada?

No setValueAt vc põe todas as colunas que você queira que o usuário altere na sua tabela. Se sua tabela não for editável, o setValueAt pode estar completamente vazio. Como no isCellEditable vc indicou que todas as suas células são editáveis, então vc precisará colocar o código para todas as colunas.

O que acontece. O seu usuário dá dois cliques numa célula, que contém um valor:

  1. O seu JTable chama o método isCellEditable para aquela célula. Se retornar true, então ele abrirá um editor e deixará o usuário editar a célula. Se o seu model retornar false, ele não deixará editar a célula;
  2. O usuário digita no editor o novo valor para a célula;
  3. O JTable chama o método setValueAt do model, indicando para ele esse novo valor. O model então atualiza o dado, se desejar;
  4. O JTable chama o método getValueAt do model, para pegar o valor. O valor obtido será exibido.

Se seu setValueAt não alterar o objeto que está dentro do model, assim que o usuário sair do editor ele voltará a ver o valor antigo, antes da edição, já que quando a tabela chegar ao passo 4, ela voltará a obter o valor não modificado. Essa é a forma padrão de tratar entradas inválidas em tabelas.

Quanto ao setValueAt, faltou colocar a linha

Amigo titulo = valores.get(row);

Logo no início, como vc fez para o getValueAt. Outra coisa. A palavra “titulo” tem a ver com livros.
Troque o nome de titulo para amigo no seu caso. :slight_smile:

Eu havia pensado em fazer um alterar da seguinte maneira:

Deixar a tabela somente para listar os registros, o usuario iria selecionar o registro e clicar no botao alterar, onde iria abrir uma tela com os dados carregados para poderem ser alterados.

public Object getValueAt(int row, int column) {
        //Precisamos retornar o valor da coluna column e da linha row.
        Amigo amigo = valores.get(row);
        if (column == COL_CODIGO) {
            return amigo.getCodigo();
        } else if (column == COL_NOME) {
            return amigo.getNome().getNome();
        } else if (column == COL_ENDERECO) {
            return amigo.getEndereco().getEndereco();
        } else if (column == COL_BAIRRO) {
            return amigo.getBairro().getBairro();
        } else if (column == COL_TELEFONE) {
            return amigo.getTelefone().getTelefone();
        }
        return ""; //Nunca deve ocorrer
    }

Neste getValueAt, esta dando ero nos gets(Nome, Endereco, Bairro e Telefone):

Qual seria a ideia de usar dois get um seguido de outro?

Ué, não é para fazer assim, por isso dá erro!

public Object getValueAt(int row, int  column) {  
       //Precisamos retornar o valor da coluna column e da linha row.  
       Amigo amigo = valores.get(row);  
       if (column == COL_CODIGO) {  
            return amigo.getCodigo();  
       } else if (column == COL_NOME) {  
           return amigo.getNome();
       } else if (column == COL_ENDERECO) {  
           return amigo.getEndereco();
       } else if (column == COL_BAIRRO) {  
           return amigo.getBairro();
       } else if (column == COL_TELEFONE) {  
             return amigo.getTelefone();  
       }  
         return ""; //Nunca deve ocorrer  
      }

Seria assim?

Isso. Tente entender o que o método está fazendo. Ele é usado pelo JTable para perguntar para seu model. “Ei, o que eu desenho na linha line, coluna row?”

Hmm… entendi.

Tenho uma duvida neste setValueAt:

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
        //Note que vc poderia alterar 2 campos ao invés de um só.
        Amigo amigo = valores.get(columnIndex);
        if (columnIndex == COL_NOME) {
            amigo.setNome(aValue.toString());
        } else if (columnIndex == COL_ENDERECO) {
            amigo.setEndereco(aValue.toString());
        } else if (columnIndex == COL_BAIRRO) {
            amigo.setEndereco(aValue.toString());
        } else if (columnIndex == COL_TELEFONE){
            amigo.setTelefone(aValue.toString());
        }
    }

Ja que e para alteração, o codigo deveria ser incluso no metodo acima?

Não entendi… que código?

Codigo do Amigo, acredito que nao deva ser alterado?

Geralmente você não deixa o usuário alterar o código. Você até pode colocar ele numa das colunas, a título de informação para seu usuário. Mas deixe-a como não editável. Pra isso, basta retornar false naquele método “isEditable” para a coluna do código.

Quem vai alterar o código é apenas o sistema, quando o Amigo for salvo (que daí sairá de -1 para o código que ele usará para sempre).

Seria dentro do metodo, isCellEditable?
Como poderia ser feita essa verificaçao?