[Resolvido] JTable não retorna a linha selecionada

Galera, boa tarde e um feliz ano novo.

Minha aplicação está me retornando uma exceção, e estou tentando entender o motivo, eu tenho o seguinte evento dentro de uma JTable.

private void tbCidadesMouseClicked(java.awt.event.MouseEvent evt) {

    Cidade c = new Cidade();
    CidadeDao dao = new CidadeDao();
    
    int row = tbCidades.getSelectedRow(); //Pego a linha selecionada.
    int id = Integer.parseInt(tbCidades.getValueAt(row, 0).toString()); // passo o valor da Id para a variavél id.
    
    c.setIdCidade(id);//seto o objeto com o valor da id;
    
    int index = dao.listar().indexOf(c); //procuro dentro do ArrayList a verdadeira posição do Objeto.
    c = dao.listar().get(index); // retorno de dentro do arrayList o objeto da classe cidade.
    
    System.out.println(dao.listar().contains(c));//Exibo uma mensagem se existe dentro do arrayList

    
    if(index>=0){
        c = dao.listar().get(index);
        
        setarCampos(c);
        habilitaCampos();
        btGravar.setEnabled(false);
        btAlterar.setEnabled(true);
        btExcluir.setEnabled(true);
    }        
}

Conforme eu vou selecionando as linhas dentro da JTable, os campos de texto vão sendo setados de acordo com o objeto, porém em determinados objetos ele gera uma exceção do tipo java.lang.ArrayIndexOutOfBoundsException: -1

Eu entendo que essa exceção significa uma posição errada dentro do ArrayList, que a linha na JTable não foi selecionada e retorna -1 para o ArrayList, porém essa linha é selecionada dentro da JTable, o que pode estar acontecendo?

1 - você deveria utilizar um ListSelectionListener para tratar seleções na JTable.

2 - você sempre está criando um novo objeto Cidade e procurando ele dentro da sua lista, se ele foi recém criado, ele não estará na lista e o dao.listar().indexOf(c) retornará -1.

3 - você chama 4 vezes o dao.listar(), deveria chamar só uma vez e armazenar a lista em uma variável local.

4 - implemente o seu proprio TableModel e renderize os elementos da lista retornada pelo seu DAO, aí, quando quiser obter um objeto da lista, basta você fazer:

int posicao = minhaTable.getSelectedIndex();
Cliente cliente = minhaLista.get(posicao);
1 curtida

A parte estranha é que essa linha de código:

int row = tbCidades.getSelectedRow(); //Pego a linha selecionada.

retorna pra mim todas as linhas da JTable, o problema é quando vou buscar esse elemento dentro do ArrayList:

int row = tbCidades.getSelectedRow();
Cidade cidade = minhaLista.get(row);

Eles seleciona cerca de 120 objetos dentro do arrayList, depois disso ele já volta a retornar o erro, percebi que dentro do meu arrayList existe sub-listas preenchidas de 0 a 99, 100 a 199, 200 a 299 e assim por diante, será que ele só busca na primeira lista?

Não, ela retorna somente o índice da linha selecionada, se não houver seleção, retorna -1.

Um ArrayList não seleciona nada, é só uma coleção de objetos.

Essas “sub-listas” que você notou são arrays, são a estrutura de dados utilizada internamente pelo ArrayList.
Um LinkedList utiliza elos encadeados para armazenar seu conteúdo.
Um ArrayList utiliza arrays, por isso se chama ArrayList.

Muito obrigado por essas informações, vou modificar o código aqui.

Ainda continuo com o erro, eu parei de carregar minha JTable utilizando o DefaultTableModel, e estou utilizando o AbstractTableModel, o meu método de setar campos funciona até determinada linha, depois aparece o erro:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException

Minha função para setar os campos está dessa forma:

private void setarCampos(){
        indice = tbEstados.getSelectedRow();
        
        PaisDao daoP = new PaisDao();
        EstadoDao dao = new EstadoDao();
        
        ArrayList<Estado> estados = new ArrayList<>(dao.listar());
        ArrayList<Pais> paises = new ArrayList<>(daoP.listar());
        
        txtCod.setText(tbEstados.getValueAt(indice, 0).toString());
        txtNome.setText(tbEstados.getValueAt(indice, 1).toString());
        txtSigla.setText(tbEstados.getValueAt(indice, 2).toString());
        
        Estado e = new Estado(Integer.parseInt(tbEstados.getValueAt(indice, 0).toString()), null, tbEstados.getValueAt(indice, 1).toString(), tbEstados.getValueAt(indice, 2).toString());
        e = estados.get(indice);
        
        for(Pais p: paises){
            if(e.getFkIdPais().equals(p.getIdPais())){
                cbBoxPais.setSelectedItem(p.getNome());
            }
        }
    }

Não consegui utilizar o

Alguém pode ajudar?

amigo, pra carregar esta tabela de cidades vc ta usando o AbstractModel ou DefaultTableModel?

Eu tive um problema parecido aqui, no meu caso, no java o indice sempre começa em 0,
mas no Banco de dados Postgres os indi8ces comeca em 1…
eu resolvi colocando +1 na variavel que armazenava o indice…

Estou utilizando o AbstractModel, acredito que o problema seja estouro de memória, afinal dentro deste ArrayList existe mais de 10.000 registros, fiz a mesma pesquisa porém com ResultSet rs utilizando o método absotule(int row), não ocorreu nenhum problema durante o processo.

Quando postar seu código, sempre selecione ele e clique no botão </> pra deixar formatado corretamente.

Não crie novas listas, seu DAO já retornam listas, é só referenciá-las diretamente.

Você já tem a lista de estados na mão, é só obter o estado da posição indice e usar ele para popular os JTextFields, não há necessidade de pegar os dados da JTable.

Aqui você instancia um estado para logo em seguida matá-lo e obter o estado da posição indice, não faz sentido.

Sem ver o código completo de suas classes, fica complicado te orientar da melhor forma.
Eu faria algo mais ou menos assim:

private void setarCampos(){
    PaisDao paisDao = new PaisDao();
    EstadoDao estadoDao = new EstadoDao();
    
    List<Estado> estados = estadoDao.listar();
    List<Pais> paises = paisDao.listar();
    
    comboBoxModelPaises.setPaises(paises);
    tableModelEstados.setEstados(estados);
	
    int indiceEstado = tableEstados.getSelectedRow();

    Estado estado = estados.get(indiceEstado);
    Pais pais = estado.getPais();

    cbBoxPais.setSelectedItem(pais.getNome());
	
    txtCod.setText(estado.getCodigo());
    txtNome.setText(estado.getNome());
    txtSigla.setText(estado.getSigla());
}

Rapaz, incrível o que a falta de experiencia faz, todos os dicas funcionaram perfeitamente bem, obrigado.