Atualizar uma jtable, que é preenchida pelo banco de dados, através de um timer

Eu tenho um jtable(já tenho uma tableModel) que basicamente sempre vai receber registros do banco de dados e vai ser inserido nela, ou seja, eu não tenho nada como um botão inserir e algo do tipo, simplesmente vai ficar aparecendo registros na jtable conforme registros são inseridos no banco de dados e para mostrar esse registros novos que foram inseridos no banco de dados lá na jtable é preciso de uma atualização na estrutura para adicionar as novas linhas. Eu fiz um método que limpa ela e adiciona a consulta dos registros, dando assim um aspecto de atualização, porém essa atualização esta sendo usada em um botão e esta funcionando 100%, o que eu quero é que deixe de ser através de um botão e agora seja feito através de um TIMER que de tempo em tempo faz essa atualização das linhas da tabela, assim mostrando as novas linhas e as modificações. Segue abaixo minha tabela:

Eu tentei colocar o TIMER no método que inicia o programa para que ele já começasse a rodar e fosse atualizando, porém da um erro que eu não sei arrumar, não sou muito experiente assim em java. Segue abaixo o código do timer:

    int delay = 5000;   // delay de 5 seg.
    int interval = 5000;  // intervalo de 5 seg.
    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            //Cada aba possui um titulo e dependendo do titulo ira fazer tal consulta.
            switch (aba) {
                case "Pendente":
                    /*Esse método usa o método que faz a consulta das ocorrências pendentes e dele pega as informações necessarias
                    para poder usar o método que adiciona linhas na jtable*/
                    consultaPendentes();
                    break;
                case "Em Atendimento":
                    /*Esse método usa o método que faz a consulta das ocorrências pendentes e dele pega as informações necessarias
                    para poder usar o método que adiciona linhas na jtable*/
                    consultaEmAtendimento();
                    break;
                default:
                    /*Esse método usa o método que faz a consulta das ocorrências pendentes e dele pega as informações necessarias
                    para poder usar o método que adiciona linhas na jtable*/
                    consultaAtendidas();
                    break;
            }
            //dei um print pra ver se tava funcionando
            System.out.println("Teste");
        }
    }, delay, interval);

O erro que ta dando quando eu executo o programa:

Teste
Exception in thread “AWT-EventQueue-0” java.lang.ArrayIndexOutOfBoundsException: 2 >= 2
at java.util.Vector.elementAt(Vector.java:474)
Teste
at javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:294)
at javax.swing.JTable$2.getMidPointAt(JTable.java:3224)
at javax.swing.JTable.adjustSizes(JTable.java:3305)
at javax.swing.JTable.setWidthsFromPreferredWidths(JTable.java:3240)
at javax.swing.JTable.doLayout(JTable.java:3128)
at java.awt.Container.validateTree(Container.java:1695)
at java.awt.Container.validateTree(Container.java:1704)
at java.awt.Container.validateTree(Container.java:1704)
at java.awt.Container.validate(Container.java:1630)
at javax.swing.RepaintManager$3.run(RepaintManager.java:711)
at javax.swing.RepaintManager$3.run(RepaintManager.java:709)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:708)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1731)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
CONSTRUÍDO COM SUCESSO (tempo total: 14 segundos)

Não sei o que fazer com esse erro, não sei o que ta dando errado no TIMER, vi uns posts aqui no forum parecidos dizendo que era erro na thread e tals e que o erro era porque tava procurando uma posição da array que não existe, ai tudo bem, mas eu não faço a minima ideia do porque dele ta pegando uma posição que não existe, não entendo nada de thread, vi sobre isso hoje, percebi que cada caso é uma coisa especifica, então eu não consegui arrumar meu erro vendo os outros posts.
Pessoal me da uma ajuda ai, mesmo vendo esses erros eu não sei pra onde ir, queria ajuda de alguém experiente para ver o código do timer e o erro.

Sem os códigos completos fica difícil de ajudar, mas se eu fosse apostar, diria que você está tentando apagar ou selecionar uma linha ou coluna da TableModel que não existe, esse erro não é do time, é da tabela. Posta os códigos ai relacionados com a tabela pra gente ver.

1 curtida

TableModel:

package model.tablemodel;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.table.AbstractTableModel;
import model.bean.OcorrenciasBean;

/**
 *
 * @author henrique
 */
public class OcorrenciasTableModel extends AbstractTableModel {

private List<OcorrenciasBean> linhas;//linhas, dados porque os dados vão ficar nas linhas
private String[] colunas = {"ID","Status","Endereço","N° de vitimas"};//colunas
// Constantes representando o índice das colunas
private static final int ID_OCORRENCIA = 0;
private static final int NUM_VITIMAS = 3;
private static final int DESC_STATUS = 1;
private static final int ENDERECO = 2;

public OcorrenciasTableModel(){
    linhas = new ArrayList<OcorrenciasBean>();
}
//nome das colunas, sem isso as colunas vão ficar com A,B,C... na ordem, ou seja, a ID ia ficar A e o Status ia ficar B.
@Override
public String getColumnName(int column) {
    return colunas[column]; //colunas vai receber A e B, e automaticamente vai substituir por Id e status
}

//linhas
@Override
public int getRowCount() {
    return linhas.size();//Tamanho da lista, ou seja, quantidade de linhas
}

//colunas
@Override
public int getColumnCount() {
    return colunas.length;//Quantidade de colunas, quantidade de colunas
}

//Pegar valores das linhas e das colunas do jtable
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    //se for coluna 1, ele entra nos case que serão as linhas, e assim vai
    OcorrenciasBean ocorrencia = linhas.get(rowIndex);//as linhas da jtable vão ser inseridas na variavel linhas que sera igual a ocorrencias.
    
    switch(columnIndex){
        case ID_OCORRENCIA:
            return ocorrencia.getIdOcorrencia();//essa linha recebe o ID de acordo com a coluna no switch
        case ENDERECO:
            return ocorrencia.getEndereco();
        case DESC_STATUS:
            return ocorrencia.getDescStatus();
        case NUM_VITIMAS:
            return ocorrencia.getNumVitimas();//essa linha recebe a descrição de acordo com a coluna no switch
    }
    
    return null;//como é um object e ele precisa de um return, é obrigado a botar o return, e no caso nos bota nulo para não interferir
}

//adiciona linhas
public void addRow(OcorrenciasBean bean){
    this.linhas.add(bean);
    int ultimoIndice = getRowCount()-1;
    this.fireTableRowsInserted(ultimoIndice, ultimoIndice);
    this.fireTableDataChanged();
}

//os campos da coluna não podem ser editados
@Override
public boolean isCellEditable(int rowIndex, int columnIndex){
    return false;
}

//define o tipo de dados que as colunas recebem, se for a coluna 0 que é meu ID, vai ser inteiro, senão for a coluna 0 então é a coluna 1 que é 
@Override
public Class<?> getColumnClass(int columnIndex){
    switch(columnIndex){
        case ID_OCORRENCIA:
            return Integer.class;
        case ENDERECO:
            return String.class;
        case DESC_STATUS:
            return String.class;
        case NUM_VITIMAS:
            return Integer.class;
        default:
            throw new IndexOutOfBoundsException("columnIndex out of bounds");
    }
}

//Esse método deixa o arraylist zerado, sendo assim ele tira todas as linhas da tabela, ou seja, ele limpa a tabela
//isso acontece porque o getRow vai pegar nenhuma linha e não vai ter o que inserir no getValue
public void limpar(){
    linhas.clear();
    this.fireTableDataChanged();
    }
}

Método que preenche a jtable com registros do banco de dados:

//Método com a estrutura de código usada para preencher a jtable.
    public void estruturaPadrao(ResultSet rs) {
        meuModelo.limpar();//Limpa a tabela

    try {
        if (!rs.next()) {//Se não tem nada no ResultSet, ou seja, se ele for nulo, a tabela é repintada.
            tbOcorr.repaint();
        } else {
            while (rs.next()) {
                OcorrenciasBean bean = new OcorrenciasBean();
                bean.setIdOcorrencia(rs.getInt(1));
                bean.setDescStatus(rs.getString(2));
                bean.setEndereco(rs.getString(3));
                bean.setNumVitimas(rs.getInt(4));
                meuModelo.addRow(bean);
                meuModelo.fireTableStructureChanged();
            }
        }
    } catch (SQLException ex) {
        Logger.getLogger(MainOcorrencias.class.getName()).log(Level.SEVERE, null, ex);
    }
    alinharEsquerda();
}

Outros códigos referentes que são utlizados lá no timer:

   //Consulta das ocorrências pendentes
    public void consultaPendentes() {
        estruturaPadrao(consulta.select());
        aba = "Pendente";
    }

//Consulta das ocorrências em atendimento
public void consultaEmAtendimento() {
    estruturaPadrao(consulta.selectEmAtendimento());
    aba = "Em Atendimento";
}

//Consulta das ocorrências atendidas
public void consultaAtendidas() {
    estruturaPadrao(consulta.selectAtendidas());
    aba = "Atendida";
}

//metódo para alinhar a coluna para a esquerda
public void alinharEsquerda() {
    DefaultTableCellRenderer esquerda = new DefaultTableCellRenderer();
    esquerda.setHorizontalAlignment(SwingConstants.LEFT);
    tbOcorr.getColumnModel().getColumn(0).setCellRenderer(esquerda);
    tbOcorr.getColumnModel().getColumn(3).setCellRenderer(esquerda);

}