[RESOLVIDO]Atualizar o JTable e mostrar a linha adicionada em tempo de execução

Olá pessoal,

Estou usando um TableModel na minha aplicação, mas não consigo atualizar os dados na JTable em tempo de execução. Tentei usar o método fireTableDataChanged() pra atualizar mas não consegui.

Classe do TableModel

public class ClienteAbstractTable extends AbstractTableModel {
    private ArrayList dados = new ArrayList();
    private String[] colunas;
    
    public ClienteAbstractTable(ArrayList dados, String[] colunas) {
        setDados(dados);
        setColunas(colunas);
       
    }
    
    public ClienteAbstractTable() {        
    }
       
    @Override
    public String getColumnName(int coluna) {
        return getColunas()[coluna];
    }
    
    @Override
    public int getRowCount() {
        return getDados().size();
    }
    
    @Override
    public int getColumnCount() {
        return getColunas().length;
    }
    
    @Override
    public Object getValueAt(int dados, int coluna) {           
        Object[] dadosLinhas = (Object[])getDados().get(dados);
            return dadosLinhas[coluna];
    }
    
    public void atualizarTabela(Cliente c) {
        this.dados.add(c);
        this.fireTableDataChanged();
    }
    
    public ArrayList getDados() {
        return dados;
    }

    public void setDados(ArrayList dados) {
        this.dados = dados;
    }

    public String[] getColunas() {
        return colunas;
    }

    public void setColunas(String[] colunas) {
        this.colunas = colunas;
    }
}

Evento do JButton

private void btnCAEditarActionPerformed(java.awt.event.ActionEvent evt) {                                            
    Cliente cli = new Cliente();
    int i = 0;
    
    try{
        cli.setCPF(txtfCAInformarCPF.getText());
        i = cbCAEditar.getSelectedIndex();
                
        switch (cbCAEditar.getSelectedIndex()) {
            case 1:
                cli.setNome(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Nome");
                break;
            case 2:
                cli.setSobrenome(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Sobrenome");
                break;
            case 3:
                cli.setDtNascimento(txtCAEditar.getText());
                lbCAAviso3.setText("Nova Data de Nascimento");
                break;
            case 4:
                cli.setEndereco(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Endereço");
                break;
            case 5:
                cli.setNumResidencia(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Numero de residência");
                break;
            case 6:
                cli.setBairro(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Bairro");
                break;
            case 7:
                cli.setCidade(txtCAEditar.getText());
                lbCAAviso3.setText("Nova Cidade");
                break;
            case 8:
                cli.setUF(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Estado");
                break;
            case 9:
                cli.setTelefone1(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Telefone");
                break;
            case 10:
                cli.setTelefone2(txtCAEditar.getText());
                lbCAAviso3.setText("Novo Telefone");
                break;
            default:
                break;
        }
                                   
                ClienteDAO.atualizar(cli, i);
                tabelaCliente.atualizarTabela(cli);
   /* tabela.preencherTabelaCliente("SELECT C.CPF, C.nome, C.sobrenome, C.nascimento, E.endereco, "
                   + "E.num, E.bairro, E.cidade, E.estado, F.fone1, F.fone2 FROM cliente C "
                   + "INNER JOIN endereco_c E on E.Cliente_CPF = C.CPF "
                   + "INNER JOIN fone_c F on F.Cliente_CPF = C.CPF", tbCPesquisa); */
    
                JOptionPane.showMessageDialog(null, "Registro de cliente atualizado com sucesso. ");            
            }catch(Exception e) {
                JOptionPane.showMessageDialog(null, "Erro ao tentar atualizar dados do cliente.");
            }    

Só consigo atualizar o JTable em tempo de execução quando chamo denovo o SQL

Se vc quer atualizar a tabela a cada adição, edição ou exclusão, é só chamar o SQL "select 'oq vc quiser' from sua_tabela" quando vc terminar algum procedimento.

EDIT

Na verdade vc já fez isso, pq deixou comentado? Não funcionou?

Sim Abner, funcionou, atualiza em tempo de execução. Só que tava lendo essa documentação que fala do TableModel https://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data e queria deixar o código mais “limpo”, ao invés de chamar o SQL pra preencher a tabela denovo, queria usar esse método fireTableDataChanged() da classe AbstractTableModel pra atualizar a tabela, mas não to conseguindo. Tá osso, ja tentei também usar o repaint() e o revalidade() e nada.

Se você está estendendo AbstractTableModel, você só precisa criar o método para tal:

public void adicionaLinha(Elemento elemento) {
    elementos.add(elemento);
    fireTableDataChanged();
}

Isso vai fazer com que, independente de qual alteração ocorreu (adicionar, excluir ou editar), a JTable seja atualizada.
Porém, é indispensável persistir as alterações, sobretudo se esta alteração se reflete no banco de dados.

Estou conseguindo guardar os dados no banco perfeitamente. No meu caso, pra cadastrar um cliente há um relacionamento no BD entre 3 tabelas, tudo certo até aí. O problema que tenho é na hora de atualizar a JTable em tempo de execução. Só consigo fazer isso se eu repreencher a tabela novamente com o SELECT, queria usar o método da propria classe AbstractTableModel.

Com a resposta do darlan, fiquei com uma dúvida: se tratando de persistência de dados no BD, tem como atualizar a JTable sem ter que dar o comando comando SELECT denovo, apenas utilizando o método fireTableDataChanged() ?

Classe do TableModel. Criei o método atualizarTabela() que tem o fireTableDataChanged() que to tentando usar:

public class ClienteAbstractTable extends AbstractTableModel {
    private ArrayList dados = new ArrayList();
    private String[] colunas;
    
    public ClienteAbstractTable(ArrayList dados, String[] colunas) {
        setDados(dados);
        setColunas(colunas);
       
    }
    
    public ClienteAbstractTable() {        
    }
       
    @Override
    public String getColumnName(int coluna) {
        return getColunas()[coluna];
    }
    
    @Override
    public int getRowCount() {
        return getDados().size();
    }
    
    @Override
    public int getColumnCount() {
        return getColunas().length;
    }
    
    @Override
    public Object getValueAt(int dados, int coluna) {           
        Object[] dadosLinhas = (Object[])getDados().get(dados);
            return dadosLinhas[coluna];
    }
    
    public void atualizarTabela(Cliente cli) {
        dados.add(cli);
        fireTableDataChanged();
    }
    
    public ArrayList getDados() {
        return dados;
    }

    public void setDados(ArrayList dados) {
        this.dados = dados;
    }

    public String[] getColunas() {
        return colunas;
    }

    public void setColunas(String[] colunas) {
        this.colunas = colunas;
    }
}

Classe que preenche a JTable com os dados carregados do banco, o método recebe como parâmetro a String SQL e a JTable usada:

public class PreencherTabela{
    private ResultSet rs;   
       
    /**
     * Preenche o JTable com os dados carregados do banco de dados. Para isso é
     * necessário informar o comando SQL e a o nome da tabela a ser utilizada.
     * @param SQL
     * @param tabela 
     */
    public void preencherTabelaCliente(String SQL, JTable tabela) {  
        ArrayList dadosCliente = new ArrayList();
        String[] colunasCliente = {"CPF", "Nome", "Sobrenome", "DataNasc.", "Endereço", "N°", "Bairro", "Cidade", "UF", "Fone1", "Fone2"};        
        
        Conexao.conectar();
        
        try {
            rs = Conexao.retornarDados(SQL);
            rs.first();
            do{ 
                dadosCliente.add(new Object[] {rs.getString("CPF"), rs.getString("nome"), rs.getString("sobrenome"),rs.getString("nascimento"), rs.getString("endereco"), rs.getString("num"), rs.getString("bairro"), rs.getString("cidade"), rs.getString("estado"), rs.getString("fone1"), rs.getString("fone2")});
            }while(rs.next());
            
        } catch (SQLException ex) {
            System.out.println("Erro ao tentar preencher tabela de clientes");
        } finally {
            Conexao.desconectar();
        }
              
        ClienteAbstractTable tabelaCliente = new ClienteAbstractTable(dadosCliente, colunasCliente);
        tabela.setModel(tabelaCliente); // 'setando' o modelo de tabela
        tabela.getTableHeader().setReorderingAllowed(false); // desabilitando reordenacao de colunas
        
        tabela.getColumnModel().getColumn(0).setPreferredWidth(77);
        tabela.getColumnModel().getColumn(0).setResizable(false);
        tabela.getColumnModel().getColumn(1).setPreferredWidth(50);
        tabela.getColumnModel().getColumn(1).setResizable(false);
        tabela.getColumnModel().getColumn(2).setPreferredWidth(130);
        tabela.getColumnModel().getColumn(2).setResizable(false);
        tabela.getColumnModel().getColumn(3).setPreferredWidth(52);
        tabela.getColumnModel().getColumn(3).setResizable(false);
        tabela.getColumnModel().getColumn(4).setPreferredWidth(160);
        tabela.getColumnModel().getColumn(4).setResizable(false);
        tabela.getColumnModel().getColumn(5).setPreferredWidth(1);
        tabela.getColumnModel().getColumn(5).setResizable(false);
        tabela.getColumnModel().getColumn(6).setPreferredWidth(70);
        tabela.getColumnModel().getColumn(6).setResizable(false);
        tabela.getColumnModel().getColumn(7).setPreferredWidth(55);
        tabela.getColumnModel().getColumn(7).setResizable(false);
        tabela.getColumnModel().getColumn(8).setPreferredWidth(2);
        tabela.getColumnModel().getColumn(8).setResizable(false);
        tabela.getColumnModel().getColumn(9).setPreferredWidth(71);
        tabela.getColumnModel().getColumn(9).setResizable(false);
        tabela.getColumnModel().getColumn(10).setPreferredWidth(81);
        tabela.getColumnModel().getColumn(10).setResizable(false);               
        
    }
}

JFrame usado na aplicação

public class TelaCliente extends JFrame {
    Usuario usu = new Usuario();
    String fkUsuarioLogado;
    int opcao = 0;

    PreencherTabela tabela = new PreencherTabela();
    ClienteAbstractTable tabelaCliente = new ClienteAbstractTable();
    
    public TelaCliente() {
        initComponents();
        setLocationRelativeTo(null);  
        tabela.preencherTabelaCliente("SELECT C.CPF, C.nome, C.sobrenome, C.nascimento, E.endereco, "
                       + "E.num, E.bairro, E.cidade, E.estado, F.fone1, F.fone2 FROM cliente C "
                       + "INNER JOIN endereco_c E on E.Cliente_CPF = C.CPF "
                       + "INNER JOIN fone_c F on F.Cliente_CPF = C.CPF", tbCPesquisa);
              
    }
    
    public void MudarCartao(String nomeCartao) {
        CardLayout  cardLayout = (CardLayout) jpCCardLayout.getLayout();
        cardLayout.show(jpCCardLayout, nomeCartao);
    }
    
    public void UsuarioLogado(String fkUsuarioLogado) {
        this.fkUsuarioLogado = fkUsuarioLogado;
    }

    private void btnCNSalvarActionPerformed(java.awt.event.ActionEvent evt) {                                            
        Cliente cli = new Cliente();
        try {
            usu.setLogin(fkUsuarioLogado);
            cli.setNome(txtCNome.getText());
            cli.setSobrenome(txtCSobrenome.getText());
            cli.setCPF(txtfCCPF.getText());
            cli.setDtNascimento(txtfCDtNascimento.getText());
            cli.setEndereco(txtCEndereco.getText());
            cli.setNumResidencia(txtCNum.getText());
            cli.setBairro(txtCBairro.getText());
            cli.setCidade(txtCCidade.getText());
            cli.setUF(cbCUF.getSelectedItem().toString());
            cli.setTelefone1(txtfCTelFixo.getText());
            cli.setTelefone2(txtfTelCelular.getText());
            cli.setUsuario(usu);
            
            ClienteDAO.inserir(cli);
            tabelaCliente.atualizarTabela(cli);
            /*tabela.preencherTabelaCliente("SELECT C.CPF, C.nome, C.sobrenome, C.nascimento, E.endereco, "
                       + "E.num, E.bairro, E.cidade, E.estado, F.fone1, F.fone2 FROM cliente C "
                       + "INNER JOIN endereco_c E on E.Cliente_CPF = C.CPF "
                       + "INNER JOIN fone_c F on F.Cliente_CPF = C.CPF", tbCPesquisa);*/            
                JOptionPane.showMessageDialog(null, "Cliente cadastrado com sucesso!");
            }catch(Exception e) {
                JOptionPane.showMessageDialog(null, "Erro ao tentar cadastrar cliente.");
            }
            
    }

Se você tem uma classe que estende de AbstracTableModel e tem o método acima, basta você pegar os dados que correspondem ao tal cliente, criar um novo objeto e invocar o método atualizarTabela.
O único porém é que, se você apresenta dados como o id da tabela cliente, por exemplo, precisa que este dado já tenha sido persistido e recuperado (se usa ORM, isso é moleza).

Tava com problema na hora de passar o objeto, acabei criando um método no próprio JFrame pra preencher a tabela. Tenho que aprender muita coisa ainda… Obrigado darlan e Abner pela ajuda.