[RESOLVIDO] Dúvida sobre migração do DefaultTableModel para AbstractTableModel - getColumnClass

No método getColumnClass, o correto é Boolean.class (com b maiúsculo):

@Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == COL_SELECIONADO) return Boolean.class; return String.class; }

O seu método isCellEditable também pode ser simplificado para:

@Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == COL_SELECIONADO; }

Bem, vou abrir um projeto separado e testar essa implementação… Se der certo, menos mal, e posto aqui o resultado…

Agora, se não conseguir, realmente devo estar fazendo algo de errado em algum detalhe do código…

Mas vou fazer isso ainda agora.

Ok, depois de colocar a classe produto como indiquei, com “throw new IllegalArgumentException” e tudo mais, o erro continuou sendo NullPointerException? Ou mudou para IllegalArgumentException?

Continuou

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at javax.swing.JTable.prepareRenderer(JTable.java:5729) at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2075) at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:1977) at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1773) at javax.swing.plaf.ComponentUI.update(ComponentUI.java:143) at javax.swing.JComponent.paintComponent(JComponent.java:763) at javax.swing.JComponent.paint(JComponent.java:1029) at javax.swing.JComponent.paintChildren(JComponent.java:864) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JViewport.paint(JViewport.java:747) at javax.swing.JComponent.paintChildren(JComponent.java:864) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124) at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:278) at javax.swing.RepaintManager.paint(RepaintManager.java:1220) at javax.swing.JComponent._paintImmediately(JComponent.java:5072) at javax.swing.JComponent.paintImmediately(JComponent.java:4882) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:803) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:714) at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:694) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:128) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Outra coisa, ainda no seu getColumnClass(). Um dos campos do seu produto é do tipo integer, então, vc deveria retornar Integer.class para essa coluna. E outro é double, então, vc também deveria retornar Double.class.

Tela:

[code]package Visao;

import Controle.acaoPesquisa;
import Controle.utilitario;
import Modelo.pesquisaTableModel;

public class formPrecos extends javax.swing.JPanel {

public formPrecos() {
    initComponents();
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    jPanel1 = new javax.swing.JPanel();
    btnPesquisa = new javax.swing.JButton();
    editPesquisa = new javax.swing.JTextField();
    jScrollPane1 = new javax.swing.JScrollPane();
    listaPalavras = new javax.swing.JList();
    jPanel2 = new javax.swing.JPanel();
    btnProximo = new javax.swing.JButton();
    painelRolagemTabela = new javax.swing.JScrollPane();
    tabelaResultado = new javax.swing.JTable();

    jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Pesquisa"));

    btnPesquisa.setText("Pesquisar");
    btnPesquisa.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            btnPesquisaActionPerformed(evt);
        }
    });

    javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
    jPanel1.setLayout(jPanel1Layout);
    jPanel1Layout.setHorizontalGroup(
        jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(editPesquisa, javax.swing.GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(btnPesquisa)
            .addContainerGap())
    );
    jPanel1Layout.setVerticalGroup(
        jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(jPanel1Layout.createSequentialGroup()
            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(btnPesquisa)
                .addComponent(editPesquisa, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );

    jScrollPane1.setViewportView(listaPalavras);

    jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Opções"));

    btnProximo.setText("Mais Resultados");

    javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
    jPanel2.setLayout(jPanel2Layout);
    jPanel2Layout.setHorizontalGroup(
        jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
            .addContainerGap(446, Short.MAX_VALUE)
            .addComponent(btnProximo)
            .addContainerGap())
    );
    jPanel2Layout.setVerticalGroup(
        jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(jPanel2Layout.createSequentialGroup()
            .addComponent(btnProximo)
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );

    tabelaResultado.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createTitledBorder("Resultado"), "Resultado"));
    //tabelaResultado.setModel(new produtosTableModel(new ArrayList<Produto>()));
    painelRolagemTabela.setViewportView(tabelaResultado);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 157, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(painelRolagemTabela, javax.swing.GroupLayout.DEFAULT_SIZE, 579, Short.MAX_VALUE)
                        .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
            .addContainerGap())
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(painelRolagemTabela, javax.swing.GroupLayout.PREFERRED_SIZE, 327, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addComponent(jScrollPane1))
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );
}// </editor-fold>                        

private void btnPesquisaActionPerformed(java.awt.event.ActionEvent evt) {                                            
    if (editPesquisa.getText().trim().length() == 0){
        utilitario.mensagemTela("Entre com o texto para pesquisar...",0);
    } else {
        btnPesquisa.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Visao/img/carregando.gif")));

        editPesquisa.setText(editPesquisa.getText().trim().toUpperCase());
        acaoPesquisa acao = new acaoPesquisa(editPesquisa.getText());
        acao.start();
        painelRolagemTabela.getVerticalScrollBar().setValue(tabelaResultado.getHeight());
        painelRolagemTabela.getHorizontalScrollBar().setValue(tabelaResultado.getWidth());
    }
}                                           

public static void setPesquisa(pesquisaTableModel modelo){
    tabelaResultado.setModel(modelo);
}

public static void setListaPalavras(String[] modelo){
    listaPalavras.setListData(modelo);
}

public static void setBotaoPesquisar(String texto){
    btnPesquisa.setText(texto);
    btnPesquisa.setIcon(null);
}

// Variables declaration - do not modify                     
private static javax.swing.JButton btnPesquisa;
private javax.swing.JButton btnProximo;
private javax.swing.JTextField editPesquisa;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private static javax.swing.JList listaPalavras;
private javax.swing.JScrollPane painelRolagemTabela;
private static javax.swing.JTable tabelaResultado;
// End of variables declaration                   

}[/code]

Ação:

[code]public class acaoPesquisa extends java.lang.Thread {

private String sql = "";
private String texto = "";

public acaoPesquisa(String texto){
    this.texto = texto;
}

@Override
public void run() {

    String[] palavras = texto.split(Pattern.quote(" "));

    for (int i = 0; i < palavras.length; i++){
        sql += formataWhereSQL(palavras[i]);

        if (i < (palavras.length - 1))
            sql += " and ";
    }

    sql = "SELECT P.id_produtos, P.descricao, P.valor, P.loja, P.link, P.data_cad FROM produtos P WHERE ativo = 'SIM' AND ("+sql+");";

    Conexao conexao = new Conexao();
    conexao.Select(sql);

    List<Produto> produtos = new ArrayList<Produto>();
    
    while(conexao.lerSelect()){
        Produto produto = new Produto(
                conexao.lerColuna("id_produtos"),
                conexao.lerColuna("descricao"),
                conexao.lerColuna("valor"),
                conexao.lerColuna("loja"),
                conexao.lerColuna("link"),
                conexao.lerColunaData("data_cad")
                );
        produtos.add(produto);
        produto = null;
    }

    if(produtos != null){
        pesquisaTableModel modelo = new pesquisaTableModel(produtos);
        formPrecos.setPesquisa(modelo);
        formPrecos.setListaPalavras(utilitario.identificaPalavras(modelo));
    } else {
        utilitario.mensagemTela("Nenhum produto foi encontrado!", 1);
    }

    conexao.fechaConn();
    conexao = null;
    formPrecos.setBotaoPesquisar("Pesquisar");
}

private String formataWhereSQL(String texto){

    texto = "(upper(P.descricao) LIKE '%"+texto+"%') ";

    return texto;
}

}
[/code]

Modelo:

public class pesquisaTableModel extends AbstractTableModel {
    private static final int COL_SELECIONADO = 0;
    private static final int COL_CODIGO = 1;
    private static final int COL_PRODUTO = 2;
    private static final int COL_VALOR = 3;
    private static final int COL_LOJA = 4;
    private static final int COL_CADASTRO = 5;

    private List<Produto> produtos = new ArrayList<Produto>();

    public pesquisaTableModel(List<Produto> produtos) {
          this.produtos = produtos;
    }

    @Override
    public int getRowCount() {
        return produtos.size();
    }

    @Override
    public int getColumnCount() {
        return 6;
    }

    @Override
    public String getColumnName(int columnIndex) {
        if (columnIndex == COL_SELECIONADO) return "X";
        if (columnIndex == COL_CADASTRO) return "Cadastro";
        if (columnIndex == COL_CODIGO) return "Código";
        if (columnIndex == COL_LOJA) return "Loja";
        if (columnIndex == COL_PRODUTO) return "Produto";
        if (columnIndex == COL_VALOR) return "Valor";
        return "";
    }

    @Override
    public Object getValueAt(int row, int column) {
        Produto produto = produtos.get(row);
        if (column == COL_SELECIONADO) return produto.estaSelecionado();
        else
        if (column == COL_CADASTRO) return produto.getCadastro();
        else
        if (column == COL_CODIGO) return produto.getCodigo();
        else
        if (column == COL_LOJA) return produto.getLink();
        else
        if (column == COL_PRODUTO) return produto.getProduto();
        else
        if (column == COL_VALOR) return produto.getValor();
        return "";
    }

    @Override
    public  void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        Produto valor = produtos.get(rowIndex);
        if (columnIndex == COL_SELECIONADO) valor.setSelecionado(Boolean.valueOf(aValue.toString()));
    }

    @Override
    public  Class getColumnClass(int columnIndex) {
        if (columnIndex == COL_SELECIONADO)
            return boolean.class;
        else
            return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        if (columnIndex == COL_SELECIONADO)
            return true;
        else
            return false;
    }

    public Produto get(int row) {
        return produtos.get(row);
    }
}

Bean Produto:

[code]public class Produto implements Serializable {

private int codigo = 0;
private String produto = "";
private double valor = 0.0;
private String link = "";
private String loja = "";
private Date cadastro = new Date();
private boolean selecionado = false;

public Produto(String codigo, String produto, String valor, String link, String loja, Date cadastro){
    this.codigo = Integer.valueOf(codigo);

    if (produto == null)
       throw new IllegalArgumentException("O produto não pode ser nulo!");
    this.produto = produto;

    this.valor = Double.valueOf(valor);

    if (link == null)
       throw new IllegalArgumentException("O link não pode ser nulo!");
    this.link = link;

    if (loja == null)
       throw new IllegalArgumentException("A loja não pode ser nula!");

    this.loja = loja;

    if (cadastro == null)
       throw new IllegalArgumentException("A data de cadastro não pode ser nula!");

    this.cadastro = cadastro;
}

public Produto(){

}

public boolean estaSelecionado() {
    return selecionado;
}

public void setSelecionado(boolean selecionado) {
    this.selecionado = selecionado;
}

public String getLoja() {
    return loja;
}

public void setLoja(String loja) {
    if (loja == null)
       throw new IllegalArgumentException("A loja não pode ser nula!");

    this.loja = loja;
}

public Date getCadastro() {
    return cadastro;
}

public void setCadastro(Date cadastro) {
    if (cadastro == null)
       throw new IllegalArgumentException("A data de cadastro não pode ser nula!");

    this.cadastro = cadastro;
}

public int getCodigo() {
    return codigo;
}

public void setCodigo(int codigo) {
    this.codigo = codigo;
}

public String getLink() {
    return link;
}

public void setLink(String link) {
    if (link == null)
       throw new IllegalArgumentException("O link não pode ser nulo!");

    this.link = link;
}

public String getProduto() {
    return produto;
}

public void setProduto(String produto) {
    if (produto == null)
       throw new IllegalArgumentException("O produto não pode ser nulo!");

    this.produto = produto;
}

public double getValor() {
    return valor;
}

public void setValor(double valor) {
    this.valor = valor;
}

}[/code]

[quote=ViniGodoy]Outra coisa, ainda no seu getColumnClass(). Um dos campos do seu produto é do tipo integer, então, vc deveria retornar Integer.class para essa coluna. E outro é double, então, vc também deveria retornar Double.class.
[/quote]

Ok, ficou:

public Class getColumnClass(int columnIndex) { if (columnIndex == COL_SELECIONADO) return boolean.class; if (columnIndex == COL_CODIGO) return int.class; if (columnIndex == COL_VALOR) return double.class; if (columnIndex == COL_CADASTRO) return Date.class; else return String.class; }

E continuou o bendito do erro! :shock:

  1. Você não precisa definir variáveis que saem de escopo como null diretamente;
  2. Você não deve concatenar Strings em código SQL, pois isso insere uma falha grave de segurança, use o preparedStatement;
  3. Você não deve concatenar Strings em for. Use para isso um StringBuilder, monte a string, e só então chame o toString();
  4. Você deve fechar a conexão e os statements dentro de um finally.
  5. Sua lista de produtos nunca será nula. Nenhum produto será encontrado quando produtos.size() == 0

Claro que nada disso pode causar o erro que você está tendo. O mais provável é que seja o problema do getColumnClass().

Aproveitando, corrija o construtor do seu modelo. Você estragou ele quando adotou a sugestão do outro colega:

O correto é mesmo:

this.produtos = new ArrayList<Produto>(produtos);

Godoy, cara, nem sei o que falar, obrigado por dispor do seu tempo, vc está me ajudando muito, fico te devendo uma cerveja! :smiley:

Vou incrementar as suas dicas nesse projeto, e testar este processo de se não trabalhar com o DefaultTM em um outro código para me facilitar a encontrar o erro…
Mas desde já, estou super agradecido pela ajuda até o momento.

Depois posto aqui os meus novos códigos para ajudar o pessoal que também possui o mesmo problema.
Vou simplificar a coisa, como no exemplo do livro para fazer tudo funcionar primeiro, e então, eu passo o código dentro das minhas necessidade, ok.

Como eu falei, o correto não é:
int.class

E sim:
Integer.class

Não é:
boolean.class

E sim:
Boolean.class

E não é:
double.class

E sim:
Double.class

YES! Blz Godoy! Deu certo agora! Nada de erros, e a tabela veio à vida!

(Já estava implementado o meu outro projeto para campo de testes, e não vou mais…)

Agora é só arrumar a tabela visualmente (alinhar texto, definir tamanho de colunas e etc), mas isso eu vou deixar para um outro post, pois vou arrumar as coisas que faltam (e que orientou durante este problema), mas já me dou como satisfeito…

Por mim, o tópico está resolvido… (vou postar a nova implementação assim que terminar, com efeito de consulta para as pessoas que estão acompanhando este tópico, e encontraram o mesmo problema)

Novamente, um grande obrigado Godoy pela sua ajuda neste domingão!
(Obs: Alterei o nome do tópico para ficar mais específico conforme o problema encontrado - facilitando assim a busca.)

Como eu costumo a brincar, se o assunto é se livrar do DefaultTableModel, minha paciência virtualmente não tem limites. 8)

1 curtida