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

35 respostas
edsonlopes

Olá a todos,
eu andei olhando na assinatura do ViniGodoy aqui do Forum, e resolvi trocar o meu DefaultTableModel pelo o método orientado nos links... Pois bem, achei legal a idéia, e creio que seja realmente mais fácil de se trabalhar com uma classe para cada tabela, enfim, implementei tudo "certo", creio eu, e depois, quando tento colocar o meu novo modelo (eu peguei como base o exemplo LivrosTableModel = http://www.guj.com.br/posts/list/132698.java#714736 ) - Que por sinal, possui alguns pequenos erros de digitação do código, mas nada grave que atrapalhe o entendimento... Voltando, no momento onde eu coloco no meu modelo, ele me gera um erro de referência nula...

pesquisaTableModel modelo = new pesquisaTableModel(produtos);
tabelaPesquisa.setModel(modelo);
Alguém poderia me dar uma luz? O erro gerado é este:
run:
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)
...
..
.

Não entendi o pq disso ao atribuir o setModel, uma vez que verifiquei, e a Lista está sendo passada direitinho, o objeto Modelo tb está sendo criado direito, e tudo mais... :?:

A minha Classe:
package Modelo;

import Modelo.Bean.Produto;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

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> valores;

    public pesquisaTableModel(List<Produto> valores) {
          this.valores = new ArrayList<Produto>(valores);
    }

    @Override
    public int getRowCount() {
        return valores.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 = valores.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 = valores.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 valores.get(row);
    }
}

35 Respostas

Nicolas_Fernandes

A JTable está instanciada?

A Lista está sendo passada direitinho, mas… Será que ela não está nula?
Ao invés de:

private  List<Produto> valores;  
   
     public pesquisaTableModel(List<Produto> valores) {  
           this.valores = new ArrayList<Produto>(valores);  
     }

Tente:

private  List<Produto> produtos = new ArrayList<Produto>();  
   
     public pesquisaTableModel( List<Produto> produtos) {  
           this.produtos = produtos;
     }
edsonlopes

Sim, eu uso um método para mudar o model da mesma:

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

E então eu uso essas linhas para passar o modelo:

pesquisaTableModel modelo = new pesquisaTableModel(produtos);
formPrecos.setPesquisa(modelo);

Onde produtos é

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

Depois de efetuar as alterações que o Nicolas orientou, ficou assim, mas mesmo assim, continua dando o erro no momento do "setModel"...

package Modelo;

import Modelo.Bean.Produto;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

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);
    }
}

Erro:

run:
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)

Cá entre nós, este não é um erro de renderização visual? Algum problema ao montar o visual da tabela?

Nicolas_Fernandes

Sim, eu uso um método para mudar o model da mesma:

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

E então eu uso essas linhas para passar o modelo:

pesquisaTableModel modelo = new pesquisaTableModel(produtos);
formPrecos.setPesquisa(modelo);

Onde produtos é

List<Produto> produtos = new ArrayList();

Eu digo a JTable, em si, não o Model dela.
Estou pergutando se há algum código, em algum lugar, assim:

JTable tableProdutos = new JTable();
       tableProdutos.setModel( new pesquisaTableModel( /*lista de produtos por parâmetro*/) );
ViniGodoy
Nicolas Fernandes:
Tente:
private  List<Produto> produtos = new ArrayList<Produto>();  
   
     public pesquisaTableModel( List<Produto> produtos) {  
           this.produtos = produtos;
     }

Atenção.
Essa sugestão não só não corrige o problema, como também insere um erro.

Fazer

this.produtos = produtos

Viola completamente o encapsulamento do model, pois permite que o usuário manipule a lista por fora da classe.

ViniGodoy

Você definiu algum renderer para sua tabela? Pode postar o código da sua interface gráfica também, onde a JTable está inserida?

O erro não acusa problema no model, mas no método prepareRenderer.

Outra coisa, certifique-se que todos os gets() do seu produto não estejam retornando null, incluindo o método estaCadastrado.
Geralmente o renderer padrão deveria tratar esse caso.

edsonlopes

Vixi... Agora não sei o que fazer... Estou perdido :-D

Meu Visual:
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 javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        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                   

}
ViniGodoy

Posta aqui:

  1. A sua classe Produto;
  2. A sua classe da janela que contém esse JTable.
edsonlopes

Classe Produto

package Modelo.Bean;

import java.io.Serializable;
import java.util.Date;

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){
        Codigo = Integer.valueOf(codigo);
        Produto = produto;
        Valor = Double.valueOf(valor);
        Link = link;
        Loja = loja;
        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) {
        this.Loja = Loja;
    }

    public Date getCadastro() {
        return Cadastro;
    }

    public void setCadastro(Date Cadastro) {
        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) {
        this.Link = Link;
    }

    public String getProduto() {
        return Produto;
    }

    public void setProduto(String Produto) {
        this.Produto = Produto;
    }

    public double getValor() {
        return Valor;
    }

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

}
ViniGodoy

Você não precisa definir um DefaultTableModel vazio para sua JTable ficar vazia. Você pode é já criar a JTable diretamente com seu produtosTableModel, criando ele com um ArrayList vazio (uma boa é definir um construtor padrão para ele).

edsonlopes

E entre o visual, e o modelo, tem uma classe de controle chamada acaoProduto, que por sua vez, prepara o array de produtos buscando na base de dados… Mas creio que está tudo certo com ela, pois ela somente faz a busca de produtos e tal… E pelo que testei aqui, ela está retornando direitinho.

edsonlopes
ViniGodoy:
Você não precisa definir um DefaultTableModel vazio para sua JTable ficar vazia. Você pode é já criar a JTable diretamente com seu produtosTableModel, criando ele com um ArrayList vazio (uma boa é definir um construtor padrão para ele).

Vc diz aqui?:

tabelaResultado.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));

Como estou usando o Netbeans, ele já cria assim que coloco na tela... Eu vou verificar se faço na mão no notepad, por fora do programa, e ver se dá certo... Mas vc acha que está aqui o problema?

ViniGodoy

Algum deses campos da classe produto pode conter o valor nulo? Se não puder, é bom validar a entrada. Aí o erro dá na atribuição, não no momento que alguém vai tentar usar o campo e acaba esbarrando no nulo.

Outra coisa. Procure seguir as convenções de código do java. Nome de atributos tem a primeira letra minúscula, de classes, a primeira letra maiúscula:

package Modelo.Bean;

import java.io.Serializable;
import java.util.Date;

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){
        codigo = Integer.valueOf(codigo);

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

        valor = Double.valueOf(valor);

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

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

        loja = loja;

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

        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;
    }
}
ViniGodoy

No próprio netbeans tem um jeito de vc definir um código personalizado para a construção do model, que substitui esse aí. Eu não lembro onde exatamente é, pq uso mais o Eclipse. Mas eu mesmo já fiz isso no próprio netbeans. Não é uma boa prática usar o Notepad para editar código que o netbeans te proíbe.

ViniGodoy

Só pra comentar. O “novo meio” que eu sugiro existe desde a invenção do JTable, já que DefaultTableModel é filho de AbstractTableModel. Esse meio também pode ser encontrado nos tutoriais da Sun ou em qualquer livro mais sério de Swing, desde os primórdios do ambiente da janelas. Esse modelo não é recomendado há bastante tempo.

edsonlopes

Obrigado pelo puxão de orelha Godoy! Eu realmente tenho esse hábito! (veio dos tempos de VB6 e Delphi! Mas vou me policiar)

Bem, eu alterei a minha classe conforme o passado, e ficou realmente melhor…

Mas o problema “java.lang.NullPointerException” ainda persiste… :frowning:

ViniGodoy

No seu model, no getValueAt() na hora de fazer o retorno da coluna Loja, você está retornando a coluna Link. Isso está errado, não?

Veja lá, está na linha 52 do código que vc postou aqui:

if (column == COL_LOJA) return produto.getLink();
edsonlopes

Ok… é que naturalmente, assim que se inicia no Java, não se vê falando disso, e sim do tal “Model” padrão que se usa nas IDE`s… Eu mesmo, fui direito aprendendo a usar o Default, pois era o que eu via ele querendo receber…

Mas assim achei realmente melhor… Agora, só falta funcionar comigo :smiley:

edsonlopes

É isso mesmo… Pois ele tem que mostrar uma coisa, e quando for requisitado, vir outra (o Link direto do produto na loja)

ViniGodoy

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; }

edsonlopes

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.

ViniGodoy

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?

edsonlopes

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)

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.

edsonlopes

Tela:

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                   

}
edsonlopes

Ação:

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;
    }


}
edsonlopes

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);
    }
}
edsonlopes

Bean Produto:

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;
    }
}
edsonlopes

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.

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:

ViniGodoy
  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().

ViniGodoy

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);
edsonlopes

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.

ViniGodoy

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

edsonlopes

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.)

ViniGodoy

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

Criado 2 de maio de 2010
Ultima resposta 2 de mai. de 2010
Respostas 35
Participantes 3