Tabelas com JTable + JFrame + JPanel

Pertence ao pacote javax.swing.
A classe javax.swing.JTable é utilizada para vizualizar dados em grid no Swing, é um dos componentes com mais recursos desse pacote. Como todo componente, o JTable deve estar inserido dentro de uma janela, ou seja, dentro de uma JFrame, como o JFrame é a versão Swing do Frame(AWT),  ao adicionarmos componentes ao JFrame teremos que utilizar o JPanel para gerenciar estes componentes O JTable possui um pacote especial, que contém diversas classes para sua utilização: javax.swing.table

Esta classe não retém os dados da tabela que ela apresenta. Ela os obtém de um modelo, representado pela classe javax.swing.table.AbstractTableModel. Isto significa que um objeto da classe javax.swing.JTable simplesmente representa a aparência e o comportamento da tabela, mas os dados que ela exibe são armazenados em um objeto da classe javax.swing.table.AbstractTableModel.

Não é necessário criar explicitamente um objeto da classe javax.swing.table.AbastractTableModel para armazenar os dados que serão exibidos em uma grade. Pode-se criar uma tabela utilizando um vetor de textos e uma matriz de objetos. O vetor de textos deve ter os títulos das colunas e a matriz de objetos deve ter os dados das linhas. Quando a tabela é criada, esses dados são armazenados em um modelo de dados padrão. Este modelo é criado automaticamente. 

A maioria dos componentes swing possuem uma arquitetura que separa model e view, de forma que é definida uma interface para cada model. Dentro deste contexto, TableModel é a interface que representa o model da JTable.
Se não informarmos qual será o model, a JTable usará por padrão uma instância de DefaultTableModel.
O DefautTableModel principal motivo complexo, motivo pelo qual não é indicado o seu uso, é muito mais difícil de matê-lo.
A JTable chama os métodos do TableModel para obter informações sobre o conteúdo da tabela, como número de linhas e colunas, conteúdo de cada célula, etc. Com estas informações em mãos, ela pode montar os dados na tela corretamente.

A classe AbstractTableModel é uma classe abstrata que oferece a implementação de alguns métodos da interface TableModel, além de um conjunto de métodos úteis. Portanto o usual é estender esta classe ao invés de implementar TableModel diretamente.

Métodos da interface TableModel:

getRowCount retorna a quantidade total de linhas. Com esta informação, a JTable sabe quantas linhas devem ser exibidas
getColumnCount retorna a quantidade total de colunas que a JTable deve usar para montar a tabela
getColumnName(int columnIndex) retorna o nome da coluna referente ao índice especificado por parâmetro. O nome da coluna é usado para definir o texto do cabeçalho
getColumnClass(int columnIndex) retorna o tipo de dado associado a coluna especificada. Esta informação é utilizada para definir o “renderer” e o “editor” que serão associados às células pertencentes a coluna em questão
isCellEditable(int rowIndex, int columnIndex) retorna um valor booleano que diz se a célula especificada pode ter seu valor alterado ou não. Isto significa que o método “setValueAt” só terá efeito se o retorno deste método for true
getValueAt(int rowIndex, int columnIndex) retorna o conteúdo da célula especificada
setValueAt(Object value, int rowIndex, int columnIndex) define um novo valor para célula especificada
addTableModelListener(TableModelListener l) adiciona o TableModelListener especificado na lista de listeners a serem notificados das mudanças nos dados da tabela
removeTableModelListener(TableModelListener l) remove o TableModelListener especificado da lista de listeners a serem notificados


Não precisamos conhecer todos os métodos da classe AbstractTableModel, mas o mais importante, os métodos “fire”, que servem para notificar a ocorrência de eventos, conforme descrito a seguir:

fireTableDataChanged notifica que todos os dados da tabela podem ter sido alterados. A JTable usa esta informação para redesenhar todas as células, atualizando seu conteúdo
fireTableStructureChanged notifica que a estrutura da tabela foi modificada. Isto significa que a quantidade, o nome ou tipo das colunas podem ter sido alteradas. Este tipo de evento faz com que a JTable reconstrua sua estrutura na tela
fireTableRowsInserted(int firstRow, int lastRow) notifica que as linhas na faixa especificada foram adicionadas, fazendo com que a JTable redesenhe apenas as linhas que foram afetadas
fireTableRowsUpdated(int firstRow, int lastRow) notifica que as linhas na faixa especificada tiveram seu valor atualizado
fireTableRowsDeleted(int firstRow, int lastRow) notifica que as linhas na faixa especificada foram removidas
fireTableCellUpdated(int row, int column) notifica que o conteúdo da célula especificada foi atualizado, fazendo com que a JTable redesenhe apenas a célula em questão

O pacote javax.swing.table

Esta pacote é extenso, é necessário uma consulta ao site oficial da Oracle para o entendimento das aplicabilidades das classes e interfaces deste pacote:
1. http://www.oracle.com/br/index.html
2. Aba Download
3. Link: Java for Developers
4. Aba: Documentação
5. Link: APIs
6. Core API Docs > 7 English

Java™ Platform, Standard Edition 7
API Specification

Package javax.swing.table

Interfaces:

Interface Description
TableCellEditor Essa interface define o método de qualquer objeto que gostaria de ser um editor de valores para componentes como JListBox , JComboBox , JTree , ou JTable necessidades de implementar.
TableCellRenderer Esta interface define o método exigido por qualquer objeto que gostaria de ser um representante para as células de uma JTable.
TableColumnModel Define os requisitos para um objeto modelo de tabela de coluna adequado para uso com JTable.
TableModel O TableModel interface especifica os métodos que o JTable irá usar para interrogar um modelo de dados tabular.

Classes:

Class Description
AbstractTableModel Esta classe abstrata fornece implementações padrão para a maioria dos métodos no TableModel interface.
DefaultTableCellRenderer A classe padrão para renderização (exibição) de células individuais em uma JTable.
DefaultTableCellRenderer.UIResource Uma subclasse de DefaultTableCellRenderer que implementa UIResource
DefaultTableColumnModel O padrão manipulador coluna para um JTable.
DefaultTableModel Esta é uma implementação do TableModel que usa um Vector de Vectors para armazenar os objetos de valor celulares.
JTableHeader Este é o objeto que gerencia o cabeçalho da JTable.
TableColumn A TableColumn representa todos os atributos de uma coluna em um JTable , largura de largura, resizibility, mínimo e máximo.
TableRowSorter<M extends TableModel> Uma implementação de RowSorter que fornece classificação e filtragem utilizando um TableModel.
TableStringConverter TableStringConverter é usado para converter objetos do modelo em cordas.


Passo 1: Criar uma janela
O primeiro passo é criar a janela em que a JTable irá ficar:

Exemplo: arquivo Janela.java

import javax.swing.JFrame;

public class Janela extends JFrame {

    public Janela() {
        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        getContentPane().setLayout(null);

        setVisible(true);
    }

    public static void main(String[] x) {
        Janela vai = new Janela();
    }
}

Execução:


Passo 2: criar os nome das coluna, cabeçalho (título) das colunas da tabela:

Nosso primeiro vetor, com apenas uma dimensão, será um vetor de String com o nome “colunas”, porque ele é o responsável por dar nome as colunas, é um array unidimensional.

Object[] colunas = new Object[]{"coluna 1", "coluna 2", "coluna 3"};

Passo 3: corpo da tabela.
O corpo da tabela é uma matriz do tipo linha por coluna, CELULAlinhacoluna onde a linha e a coluna são índices que coneçam com zero e terminam com a dimensão da tabela.

Coluna 0
Coluna 1
Coluna 2
CELULA00 CELULA01 CELULA02
CELULA10 CELULA11 CELULA12
CELULA20 CELULA21 CELULA22

Object[][] valores = new Object[3][3];

Obs: esta tabela tem 3 linha por 3 colunas, os indices dos mesmos vão de 0 a 2.

Passo 4: inserindo valores no JTable:
Embora a tabela não tenha sido criada ainda, utiliza-se um loop for para inserir todos os dados da tabela de uma só vez, observe que cada loop inseri um linha por vez, compare com a tabela acima.

Object[][] valores = new Object[3][3];
for (int i = 0; i < 3; i++) {

valores[i][0] = "linha "+i+"coluna "+0;

valores[i][1] =
"linha "+i+"coluna "+1;
valores[i][2] =
"linha "+i+"coluna "+2;
}


Passo 5: criar a tabela de fato:

JTable table = new JTable(valores, colunas);


Exemplo 1:

Arquivo tabela2.java

package pacote3;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class Tabela2 extends JFrame {
    // Instance attributes used in this example
    private JPanel topPanel;
    private JTable table;
    private JScrollPane scrollPane;

    public Tabela2() {
        // configuração do JFrame
        setTitle("Uma Tabela Simples");
        setSize(300, 200);
        setBackground(Color.gray);

        // Cria o painel
        topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());
        getContentPane().add(topPanel);

        // Cria os nomes das colunas

        Object[] colunas = new Object[] { "coluna 1", "coluna 2", "coluna 3" };

        // Cria os dados, array com 3 linha e 3 colunas

        Object[][] valores = new Object[3][3];
        for (int i = 0; i < 3; i++) {
            valores[i][0] = "linha" + i + " coluna" + 0;
            valores[i][1] = "linha" + i + " coluna" + 1;
            valores[i][2] = "linha" + i + " coluna" + 2;
        }

        // Cria o JTable
        table = new JTable(valores, colunas);

        // Adiciona o JTable dentro do painel
        scrollPane = new JScrollPane(table);
        topPanel.add(scrollPane, BorderLayout.CENTER);
    }

    public static void main(String args[]) {
        // Executa o JFrame
        Tabela2 vai = new Tabela2();
        vai.setVisible(true);
    }
}

Execução:



Exemplo 2:

O mesmo exemplo acima, porém utilizando array de String para o nome das colunas e seu corpo no lugar array de objetos.

Arquivo: Tabela1.java
class Tabela1 extends JFrame {
    // Atributos
    private JPanel topPanel;
    private JTable table;
    private JScrollPane scrollPane; // para rolar o painel

    public Tabela1() {
        // configuração do JFrame
        setTitle("Uma Tabela Simples");
        setSize(300, 200);
        setBackground(Color.gray);

        // Cria o painel
        topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());
        getContentPane().add(topPanel);

        // Cria os nomes das colunas
        String colunas[] = { "Móveis", "Eletro", "Utensílios" };

        // Cria os dados
        String valores[][] = { { "Sofá", "TV", "Faca" },
                { "Cama", "Aspirador", "Colher" },
                { "Mesa", "Lavadora", "Garfo" },
                { "Cadeira", "Liquidificador", "Copo" } };

        // Cria o JTable
        table = new JTable(valores, colunas);

        // Confirua  o JTable com JScrollPane e este últino é adicionado dento do JPanel
        scrollPane = new JScrollPane(table);
        topPanel.add(scrollPane, BorderLayout.CENTER);
    }

    public static void main(String args[]) {
        // Executa o JFrame
        Tabela1 vai = new Tabela1();
        vai.setVisible(true);
    }
}

Execução:


Observações:
O JScrollPane não aparece porque o JTable é menor que o JFrame.
A figura abaixo mostra a insersão dos componentes:


A vantagem de utilizar o array com os nomes das colunas é que se um dia acrescentarmos novas colunas à tabela, não precisaremos modificar os métodos “getColumnCount” e “getColumnName”, bastará acrescentar o nome da nova coluna no array.

Model View Controller
JTable É um componente MVC: o seu trabalho é dividido em 3 partes:

Model: É a parte que cuida dos dados, quem controla e distribui os dados na jtable. É implementado pela interface TableModel ( AbstractTableModel e DefaultTableModel ). Ela é responsavel por fornecer os dados para a tabela através do método Object getValueAt(row, col), informando a linha e a coluna. Este método retorna um Object, ou seja, um objeto qualquer, que pode ser um Integer, uma String ou uma outra classe que tenha sido implementado.

View: É a parte que cuida da apresentação. É implementado pela interface CellRenderer. É como a apresentação é dada celula a celula na tabela, o renderer deve ser fornecedido para uma celula especifica. Na Jtable é possivel fornecer tanto um renderer para a tabela inteira como para uma coluna especifica. Assim como na tablemodel requisitará o valor na linha e coluna especifica, aqui ele requisitará o objeto que ira apresentar o dados, passando como parâmetro a linha, a coluna o valor (object), a tabela (jtable), se esta celula esta selecionada e se esta celula possui o foco. Este método é o getCellRendererComponent, que irá retornar um JComponent. O DefaultCellRenderer implementa o JLabel para apresentar os dados, que é a forma de apresentação mais comum para um valor.

Controller: É a parte que controla a apresentação dos dados na view. É a própria JTable. Como a JTable já vem implementada para usar os tipos defaults existentes e implementados, para criar uma jtable simples não é tão complicado. O problema é que um programa muito simples os recursos são limitados.


Criando uma JTable

Fornecedor os dados que quero exibir nela.

Método
Descrição
getValueAt() recupera os dados de uma dada linha e coluna como um Object, enquanto setValueAt() atribui um valor a uma determinada célula
getColumnClass()  retorna a Class que descreve os objetos armazenados em uma determinada coluna (usado para atribuir um renderizador e editor padrão para tal coluna)
getColumnName() retorna o nome associado com uma coluna. Os métodos getColumnCount() e getRowCount() retornam o número de colunas e linhas.
isCellEditable() retorna true se a célula em uma dada linha e coluna puder ser editada


table.getModel().getValueAt(1, 1);

table.getModel().setValueAt(“aaa”, 1, 1);

O método setValueAt() deve ser implementado de forma que, se o método isCellEditable() retornar false, o conteúdo da célula no local espeficado não seja atualizado.

Este modelo suporta a inclusão de TableModelListeners, que devem ser notificados quando há alteração no conteúdo do modelo. Como esperado, métodos para adicionar e remover estes ouvintes de eventos são fornecidos, addTableModelListener(), removeTableModelListener(), entre outros.

Cada JTable usa uma instância de TableModel que pode ser atribuida ou obtida usandos os métodos setModel() e getModel() da classe JTable.


JTable(TableModel dm)

Instâncias de TableModel são responsáveis pela armazenagem dos dados de uma tabela em uma estrutura bidimensional tais como um vetor bidimensional ou um Vector de Vector. Um conjunto de métodos é declarado para auxiliar o trabalho de recuperação dos dados contidos nas células da tabela. 

A TableModel é uma interface que possui os seguintes métodos que serão implementados (alguns) no próximo exemplo:

Métodos da Interface TableModel

Método
Descrição
void addTableModelListener(TableModelListener ouvinte)
Class getColumnClass(int índice)
int getColumnCount() Retorna o número de colunas do modelo
String getColumnName(int indexColuna) Retorna o nome da coluna que está no índice passado por parâmetro
int getRowCount() Retorna o número de linhas da Tabela
Object getValueAt(int linhaIndex, int colunaIndex) Retorna o objeto presente na célula que está na linha de índice linhaIndex e na coluna colunaIndex
boolean isCellEditable(int linhaIndex, int colunaIndex) Retorna true se a célula que está na linha linhaIndex e na coluna colunaIndex. Este método não precisa ser implementado se você não quiser que as células da sua tabela sejam editáveis
void removeTableModelListener(TableModelListener ouvinte)
void setValueAt(Object valor, int linhaIndex, int colunaIndex) Este método coluna na célula de linhaIndex e colunaIndex o Object valor.???

Com esses métodos implementados, se consegue construir tabelas com próprios modelos, os quais podem ser alterados no meio da execução do programa.

A classe TesteTableModel irá desmonstrar algumas das opções que temos com nossa Table Model.

Exemplo 3:

Classe Pessoa

public class Pessoa {

    private String nome;
    private String estado;
    private String cidade;

    public Pessoa(String nome, String cidade, String estado) {
        setNome(nome);
        setCidade(cidade);
        setEstado(estado);
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }

    public String getCidade() {
        return cidade;
    }

    public void setCidade(String cidade) {
        this.cidade = cidade;
    }
}

Classe MinhaTableModel

import javax.swing.table.AbstractTableModel;

public class MinhaTableModel extends AbstractTableModel {

    private String[] tituloColunas;
    private Object[][] data;
    private int linhas, colunas;

    /**
     * Construtor que recebe o número de linhas e colunas e um vetor com o nome
     * das colunas
     *
     * @param tituloColunas vetor com o título das colunas
     * @param numLinhas número de linhas da table
     * @param numColunas número de colunas da table
     */
    public MinhaTableModel(String[] tituloColunas, int numLinhas, int numColunas) {
        this.tituloColunas = tituloColunas;
        this.data = new Object[numLinhas][numColunas];
        linhas = numLinhas;
        colunas = numColunas;
    }

    /**
     * @param col indice da coluna a ser retornado o título da coluna
     * @return Retorna o nome da coluna no index col
     */
    public String getColumnName(int col) {
        return tituloColunas[col];
    }

    /**
     * @return retorna o número de colunas da table
     */
    @Override
    public int getColumnCount() {
        return colunas;
    }

    /**
     * @return retorna o número de linhas da table
     */
    @Override
    public int getRowCount() {
        return linhas;
    }

    /**
     * @return retorna o objeto que está na posição linha x coluna passados
     * como parâmetro
     */
    @Override
    public Object getValueAt(int linha, int coluna) {
        return data[linha][coluna];
    }

    /**
     * seta o valor da linha x coluna com o objeto passado
     */
    public void setValueAt(Object valor, int linha, int coluna) {
        data[linha][coluna] = valor.toString();
        fireTableCellUpdated(linha, coluna);
    }
}

Classe TesteTableModel

    import java.awt.Dimension;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
     
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.WindowConstants;
    
    
    public class TesteTableModel extends JFrame {
          
            private JTextField jtf_nome;
            private JTextField jtf_estado;
            private JTextField jtf_cidade;
            private JButton incluir;
            private JButton limpar;
          
            private JTable table;
            private JScrollPane jsp;
          
            private JPanel main;
            private JPanel dados;
            private JPanel tableDados;
          
            private ArrayList<Pessoa> p;
          
            public TesteTableModel(){
                    super("Exemplo de Mable Model");
                    this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                    jtf_nome = new JTextField(15);
                    jtf_estado = new JTextField(15);
                    jtf_cidade = new JTextField(15);
                    incluir = new JButton("Incluir");
                    limpar = new JButton("Limpar");
                    main = new JPanel();
                    dados = new JPanel(new GridLayout(4, 2));
                    tableDados = new JPanel();
                    jsp = new JScrollPane();
                    p = new ArrayList<Pessoa>();
                    table= new JTable();
            }
          
            private void execute(){
                    adicionarListeners();
                    modelaTela();
            }
          
            private void adicionarListeners() {
                    incluir.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                    if(jtf_nome!=null && jtf_nome.getText().equals("")==true){
                                            JOptionPane.showMessageDialog(null, "Digite o nome");
                                    }
                                    else if(jtf_cidade!=null && jtf_cidade.getText().equals("")==true){
                                            JOptionPane.showMessageDialog(null, "Digite a cidade");
                                    }
                                    else if(jtf_estado!=null && jtf_estado.getText().equals("")==true){
                                            JOptionPane.showMessageDialog(null, "Digite o estado");
                                    }
                                    else{
                                            p.add(new Pessoa(jtf_nome.getText(), jtf_cidade.getText(), jtf_estado.getText()));
                                            limpar();
                                            listar();
                                    }
                            }
    
                          
                    });
                    limpar.addActionListener(new ActionListener() {
                          
                            @Override
                            public void actionPerformed(ActionEvent arg0) {
                                    limpar();
                            }
                    });
            }
          
            private void limpar() {
                    jtf_nome.setText("");
                    jtf_cidade.setText("");
                    jtf_estado.setText("");
                  
            }
          
            private void listar() {
                    table.setModel(new MinhaTableModel(new String[]{"Nome", "Cidade", "Estado"}, p.size(), 3));
                    for(int i=0; i<p.size(); i++){
                            table.setValueAt(p.get(i).getNome(), i, 0);
                            table.setValueAt(p.get(i).getCidade(), i, 1);
                            table.setValueAt(p.get(i).getEstado(), i, 2);
                    }
                  
                    jsp.setViewportView(table);
                    jsp.setAutoscrolls(true);
                    table.setAutoCreateRowSorter(true);
                  
            }
          
            private void modelaTela(){
                    dados.add(new JLabel("Nome:"));
                    dados.add(jtf_nome);
                    dados.add(new JLabel("Estado:"));
                    dados.add(jtf_estado);
                    dados.add(new JLabel("Cidade:"));
                    dados.add(jtf_cidade);
                    dados.add(incluir);
                    dados.add(limpar);
                    table.setModel(new MinhaTableModel(new String[]{"Nome", "Cidade", "Estado"}, 0, 3));
                    jsp.setViewportView(table);
                    tableDados.add(jsp);
                  
                    main.add(dados);
                    main.add(tableDados);
                  
                    this.setContentPane(main);
                    this.setSize(600,700);
                    this.setVisible(true);
            }
          
            public static void main(String[] args){
                    TesteTableModel t = new TesteTableModel();
                    t.execute();
     }
}

run:

 

Após inserir os dados e clicar no boltão Incluir será mostrado os dados na tabela.


Exemplo 4:

Programa ExemploJTable

import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;

public class ExemploJTable extends JFrame implements ActionListener {
    JTable tabela;
    Modelo modelo;
    JButton btn;

    public ExemploJTable() {
        String colunas[] = { "Nome", "Endereço", "Telefone", "UF", "Ativo" };
        Object dados[][] = {
                { "João", "Rua Tal", "4444", "SP", new Boolean(true) },
                { "Maria", "Av Tal", "3333", "SP", new Boolean(false) } };
        modelo = new Modelo(dados, colunas);
        tabela = new JTable(modelo);

        TableColumn uf = tabela.getColumnModel().getColumn(3);

        String[] siglas = { "AC", "BA", "MG", "SP" };
        JComboBox comboUf = new JComboBox();
        for (String sigla : siglas) {
            comboUf.addItem(sigla);
        }
        uf.setCellEditor(new DefaultCellEditor(comboUf));

        JScrollPane sp = new JScrollPane(tabela);
        add(sp, "Center");

        btn = new JButton("MostraCelulaSelecionada");
        btn.addActionListener(this);
        add(btn, "South");
        pack();
        setVisible(true);

    }

    public void actionPerformed(ActionEvent evt) {
        int linha = tabela.getSelectedRow();
        int coluna = tabela.getSelectedColumn();
        if (linha != -1 && coluna != -1) {
            Object dado = tabela.getValueAt(linha, coluna);
            JOptionPane.showMessageDialog(this, dado);
        } else {
            JOptionPane.showMessageDialog(this, "Nenhuma célula selecionada");
        }
    }

    public static void main(String[] args) {
        new ExemploJTable();
    }

    class Modelo extends AbstractTableModel {

        Object[][] dados;

        String[] colunas;

        public Modelo(Object[][] dados, String[] colunas) {
            this.dados = dados;
            this.colunas = colunas;
        }

        public int getColumnCount() {
            return dados[0].length;
        }

        public int getRowCount() {
            return dados.length;
        }

        public Object getValueAt(int linha, int coluna) {
            return dados[linha][coluna];
        }

        public String getColumnName(int coluna) {
            return colunas[coluna];
        }

        public boolean isCellEditable(int row, int col) {
            return true;
        }

        public void setValueAt(Object valor, int linha, int coluna) {
            dados[linha][coluna] = valor;
            fireTableCellUpdated(linha, coluna);
        }

        public Class getColumnClass(int coluna) {
            return getValueAt(0, coluna).getClass();
        }
    }
}


run:

Coluna UF

Obs:

Classe AbstractTableModel

public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);


Usando um JComboBox como editor

TableColumn uf = nomeTabela.getColumnModel().getColumn(coluna);

String[] siglas = {"AC", "BA", "MG", "SP"};
JComboBox comboUf = new JComboBox();
for (String sigla : siglas) {
   comboUf.addItem(sigla);
}
uf.setCellEditor(new DefaultCellEditor(comboUf));


Exibindo valores booleanos com JCheckBox

public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); }


Exemplo 5:

Inserindo arquio texto em uma JTable


Classe: CVSTableModel

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;

/**
 * Desenha o arquivo cvs.
 */
public class CVSTableModel extends AbstractTableModel {

    List<String> lines = new ArrayList<String>();
    private String[] columnNames;

    public CVSTableModel(String... columnNames) {
        this.columnNames = columnNames;
    }

    public void add(String line) {
        lines.add(line);
        fireTableRowsInserted(lines.size() - 1, lines.size() - 1);
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return lines.size();
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        //Usamos novamente o split para separar as colunas da linha desejada
        String[] colunas = lines.get(rowIndex).split(",");

        //Retornamos a coluna desejada
        return colunas[columnIndex];
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column];
    }
}


Classe: FrameComTable

import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.FileReader;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JScrollPane;

public class FrameComTable extends JFrame {

    private static final long serialVersionUID = 1L;
    private JPanel jContentPane = null;
    private JButton btnLerDoCvs = null;
    private JFileChooser chooser;
    private JScrollPane scrlTabela = null;
    private JTable tblTabela = null;

    /**
     * This is the default constructor
     */
    public FrameComTable() {
        super();
        initialize();
    }

    /**
     * This method initializes this
     *
     * @return void
     */
    private void initialize() {
        this.setSize(385, 277);
        this.setContentPane(getJContentPane());
        this.setTitle("JFrame");
    }

    /**
     * This method initializes jContentPane
     *
     * @return javax.swing.JPanel
     */
    private JPanel getJContentPane() {
        if (jContentPane == null) {
            jContentPane = new JPanel();
            jContentPane.setLayout(new BorderLayout());
            jContentPane.add(getBtnLerDoCvs(), BorderLayout.SOUTH);
            jContentPane.add(getScrlTabela(), BorderLayout.CENTER);
        }
        return jContentPane;
    }

    /**
     * This method initializes btnLerDoCvs
     *
     * @return javax.swing.JButton
     */
    private JButton getBtnLerDoCvs() {
        if (btnLerDoCvs == null) {
            btnLerDoCvs = new JButton();
            btnLerDoCvs.setText("Ler do CVS");
            btnLerDoCvs.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent e) {
                    onLerDoCVS();
                }
            });
        }
        return btnLerDoCvs;
    }

    private JFileChooser getChooser() {
        if (chooser == null) {
            chooser = new JFileChooser();
        }
        return chooser;
    }

    /**
     * Lemos do arquivo CVS.
     */
    protected void onLerDoCVS() {
        JFileChooser chooser = getChooser();
        if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) {
            return;
        }

        try {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(
                        chooser.getSelectedFile()));

                //Leitura do cabeçalho
                String line = reader.readLine();
                if (line == null) {
                    throw new RuntimeException(
                            "O arquivo não tem linhas suficientes para ser exibido!");
                }

                //Criamos nosso model com o cabeçalho
                //O split separa as colunas.
                CVSTableModel model = new CVSTableModel(line.split(","));

                //Leitura das linhas
                line = reader.readLine();
                while (line != null) {
                    model.add(line); // Cada linha lida entra no model
                    line = reader.readLine();
                }
                //Definimos nosso model na table.
                getTblTabela().setModel(model);
            } finally {
                //É necessário finalizar os recursos.
                //Garantimos isso num finally.
                if (reader != null) {
                    reader.close();
                }
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, e.getMessage());
        }
    }

    /**
     * This method initializes scrlTabela
     *
     * @return javax.swing.JScrollPane
     */
    private JScrollPane getScrlTabela() {
        if (scrlTabela == null) {
            scrlTabela = new JScrollPane();
            scrlTabela.setViewportView(getTblTabela());
        }
        return scrlTabela;
    }

    /**
     * This method initializes tblTabela
     *
     * @return javax.swing.JTable
     */
    private JTable getTblTabela() {
        if (tblTabela == null) {
            tblTabela = new JTable();
        }
        return tblTabela;
    }

    public static void main(String[] args) {
        new FrameComTable().setVisible(true);
    }
}


Arquivo texto: cvs.txt

Nome, Idade, Profissão
Vinícius Godoy, 27, Desenvolvedor de jogos
Luíz Inácio Lula da Silva, 62, Presidente da Republica(?)
Cebolinha, 7, Personagem em quadrinhos


Execução da classe: FrameComTable

run:

Ao clicar no botão Ler do CVS

Ao abrir o arquivo cvs.txt


Exemplo 6:

O grande segredo está na criação do objeto JTable:

table.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] { },
new String [] {
//aqui adiciona-se as colunas e seus respectivos nomes
" ","Nome", "Telefone","email","Sexo"
}
){}

Seta-se aqui um setModel() no objeto do JTable e como parâmetro passamos dinâmicamente um objeto javax.swing.table.DefaultTableModel com o nome de todas as colunas.

Depois pode-se usar esses comandos para inserir linhas vazias

javax.swing.table.DefaultTableModel
dtm = (javax.swing.table.DefaultTableModel)table.getModel();
//lembre-se um "" para cada coluna na tabela
dtm.addRow(new Object[]{"","","","",""});

E este para apagar qualquer linha da tabela

int[] l = table.getSelectedRows();//captura as linhas selecionadas

//pega o DefaultTableModel da tabela
javax.swing.table.DefaultTableModel dtm = (javax.swing.table.DefaultTableModel)table.getModel();

for(int i = (l.length-1);
i >= 0; –i) {
dtm.removeRow(l[i]);//remove todas as linhas selecionadas
}

Como não podemos adicionar ou remover diretamente na tabela temos que criar um objeto DefaultTableModel que possa receber o objeto.

javax.swing.table.DefaultTableModel
dtm = (javax.swing.table.DefaultTableModel)table.getModel();

O objeto passa a ser o dtm só para ser usado em adições e exclusões de linhas, mas para setar valores e pegar valores podemos usar os métodos da classe Jtable mesmo (ex: table.getValueAt(1,3)).

Para dar uma tamanho pré-definido e para cada coluna usa-se o seguinte comando, onde getColumn() recebe o index da coluna e o setPreferredWidth() recebe o tamanho que terá a coluna escolhida:

table.getColumnModel().getColumn(1).setPreferredWidth(150);

Outro curiosidade é o fato de se poder adicionar qualquer objeto em uma célula de um Jtable, seja imagem, botões, radio buttons, list, enfim, quase tudo. Para demonstrar isso inserir um JcomboBox na última coluna com o seguinte comando:

table.getColumn(table.getColumnName(1)).setCellEditor( new javax.swing.DefaultCellEditor(scmbSexo));


package JTable1;

public class ExemploJTable extends javax.swing.JFrame {

    /**
     * Creates new form ExemploJTable
     */
    public ExemploJTable() {

        String[] sexos = {"M", "F"};
        scmbSexo = new javax.swing.JComboBox(sexos);
        initComponents();
        /**
         * Este evento adiciona uma linha vazia na tabela
         *
         */
        bMais.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                javax.swing.table.DefaultTableModel dtm = (javax.swing.table.DefaultTableModel) table.getModel();
                dtm.addRow(new Object[]{"", "", "", "", ""});
            }
        });

        /**
         * Este evento exclui as linhas vazias que foram selecionadas na tabela
         *
         */
        bMenos.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                int[] l = table.getSelectedRows();
                javax.swing.table.DefaultTableModel dtm = (javax.swing.table.DefaultTableModel) table.getModel();

                for (int i = (l.length - 1); i >= 0; --i) {
                    if ("".equals(table.getValueAt(l[i], 1).toString().trim())) {
                        dtm.removeRow(l[i]);

                    }
                }
            }
        });

    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        bAdd = new javax.swing.JPanel();
        pnTable = new javax.swing.JPanel();
        scrollTable = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();
        bMenos = new javax.swing.JButton();
        bMais = new javax.swing.JButton();
        jButton1 = new javax.swing.JButton();
        bDelete = new javax.swing.JButton();

        setTitle("Exemplo JTable imasters");
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        bAdd.setLayout(null);

        pnTable.setLayout(new java.awt.GridLayout(1, 0));

        pnTable.setBorder(new javax.swing.border.TitledBorder("Exemplo de JTable"));
        table.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{},
                new String[]{
            " ", "Nome", "Telefone", "email", "Sexo"
        }) {
        });
        table.getColumnModel().getColumn(0).setPreferredWidth(10);
        table.getColumnModel().getColumn(0).setResizable(false);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(1).setResizable(true);
        table.getColumnModel().getColumn(2).setPreferredWidth(60);
        table.getColumnModel().getColumn(2).setResizable(true);
        table.getColumnModel().getColumn(3).setPreferredWidth(160);
        table.getColumnModel().getColumn(3).setResizable(true);
        table.getColumn(table.getColumnName(4)).setCellEditor(new javax.swing.DefaultCellEditor(scmbSexo));
        table.getColumnModel().getColumn(4).setPreferredWidth(30);
        table.getColumnModel().getColumn(4).setResizable(true);
        table.getTableHeader().setReorderingAllowed(false);
        table.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
        scrollTable.setViewportView(table);

        pnTable.add(scrollTable);

        bAdd.add(pnTable);
        pnTable.setBounds(10, 10, 370, 230);

        bMenos.setText("-");
        bAdd.add(bMenos);
        bMenos.setBounds(400, 110, 40, 40);

        bMais.setText("+");
        bAdd.add(bMais);
        bMais.setBounds(400, 60, 40, 40);

        jButton1.setText("Add");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        bAdd.add(jButton1);
        jButton1.setBounds(390, 180, 60, 23);

        bDelete.setText("Del");
        bDelete.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bDeleteActionPerformed(evt);
            }
        });

        bAdd.add(bDelete);
        bDelete.setBounds(390, 210, 60, 23);

        getContentPane().add(bAdd, java.awt.BorderLayout.CENTER);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width - 474) / 2, (screenSize.height - 283) / 2, 474, 283);
    }//GEN-END:initComponents

    private void bDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bDeleteActionPerformed
        // TODO add your handling code here:
        int[] l = table.getSelectedRows();
        javax.swing.table.DefaultTableModel dtm = (javax.swing.table.DefaultTableModel) table.getModel();

        for (int i = (l.length - 1); i >= 0; --i) {
            dtm.removeRow(l[i]);
        }
    }//GEN-LAST:event_bDeleteActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        // TODO add your handling code here:
        javax.swing.table.DefaultTableModel dtm = (javax.swing.table.DefaultTableModel) table.getModel();
        dtm.addRow(new Object[]{" ", "Almedson Ferreira", "1111111", "aferreira@agrovale.com", "M"});
    }//GEN-LAST:event_jButton1ActionPerformed

    /**
     * Exit the Application
     */
    private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
        System.exit(0);
    }//GEN-LAST:event_exitForm

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        new ExemploJTable().show();
    }
    private javax.swing.JComboBox scmbSexo;
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel bAdd;
    private javax.swing.JButton bDelete;
    private javax.swing.JButton bMais;
    private javax.swing.JButton bMenos;
    private javax.swing.JButton jButton1;
    private javax.swing.JPanel pnTable;
    private javax.swing.JScrollPane scrollTable;
    private javax.swing.JTable table;
    // End of variables declaration//GEN-END:variables
}

Resultado

Obs:

O primeiro botão adiciona uma linha em banco

O segundo botaõ apaga a linha em branco selecionada

O terceiro botão adiciona um registro previamente já incluido

O quarto botão apaga qualquer linha selecionada.


Exemplo 7:

Primeiro  deve-se criar uma nova classe que estenda AbstractTableModel e customizá-la para exibir os dados que se quer. Parecer meio desnecessário escrever uma classe para cada tabela do seu sistema (ou uma genérica), mas isso compensa muito na hora de utilizá-la, e compensa mais ainda na hora de reutilizá-la (o famoso reuso da orientação a objetos).

O escopo será o seguinte: uma loja qualquer quer controlar seu estoque. Em algum lugar dentro do software que realizará esta tarefa vai ter uma tela de consulta dos produtos e suas respectivas quantidades disponíveis em estoque.

Uma tela de consulta de produtos com alguns botões só para demonstrar o funcionamento do modelo.

Abra o NetBeans, crie um novo projeto para área de trabalho, crie um novo pacote, crie um novo JFrame dentro dele e deixe parecido com este:

O JFrame contém os seguintes componentes:

1 JTable (que já vem dentro do seu JScrollPane)

5 JButtons

Os textos dos botões já explicam qual será a função de cada um deles certo?

A classe base (da camada de modelo)  vai representar os produtos do  controle de estoque. Segue a classe Produto.java:

public class Produto {

    private int cod;
    private String nome;
    private int quant;

    public Produto() {
    }

    public Produto(int cod, String nome, int quant) {
        this.cod = cod;
        this.nome = nome;
        this.quant = quant;
    }

    public int getCod() {
        return cod;
    }

    public void setCod(int cod) {
        this.cod = cod;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getQuant() {
        return quant;
    }

    public void setQuant(int quant) {
        this.quant = quant;
    }
}


O próximo passo é criar uma classe que herde de AbstractTableModel. A classe AbstractTableModel define alguns métodos que se pode reescrever para criar um modelo bem mais fácil de trabalhar. Seguem os métodos, que vão ser utilizados neste exemplo, e suas respectivas funções:

int getRowCount() -> retorna o número de linhas que a tabela tem;

int getColumnCount() -> retorna o número de colunas que a tabela tem;

String getColumnName(int column)-> retorna o nome que será exibido na coluna (o índice da primeira coluna é 0);

Class<?> getColumnClass(int columnIndex) -> retorna a classe que representa cada coluna. String irá mostrar o texto alinhado à esquerda, Integer irá mostrar o número alinhado à direita, Boolean irá mostrar um checkbox… ;

Object getValueAt(int rowIndex, int columnIndex) -> método utilizado pela JTable para escrever os valores nas células. Internamente a JTable passa em todas as celulas chamando este método para poder setar os valores;

??void setValueAt(Object aValue, int rowIndex, int columnIndex) -> método que a JTable chama quando uma célula é editada;

boolean isCellEditable(int rowIndex, int columnIndex) -> método para saber se a célula é ou não editável;

void fireTableDataChanged() -> método que avisa todos os listeners da tabela que houve uma mudança nos dados, um deles é o responsável por desenhar a tabela e ao ser notificado irá redesenhá-la.


Arquivo ProdutoTableModel.java


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class ProdutoTableModel extends AbstractTableModel {

    //constantes que vão representar as colunas
    //(só para facilitar o entendimento do código)
    private final int COL_NOME = 0;
    private final int COL_QUANT = 1;
    //lista dos produtos que serão exibidos
    private List<Produto> prp;
    private List<Produto> produtos;
   

    public ProdutoTableModel() {
        produtos = new ArrayList();
    }

    public ProdutoTableModel(List<Produto> lista) {
        this();
        produtos.addAll(lista);
    }

    public int getRowCount() {
        //cada produto na lista será uma linha
        return produtos.size();
    }

    public int getColumnCount() {
        //vamos exibir só Nome e Quantidade, então são 2 colunas
        return 2;
    }

    @Override
    public String getColumnName(int column) {
        //qual o nome da coluna
        if (column == COL_NOME) {
            return "Nome";
        } else if (column == COL_QUANT) {
            return "Quant. Disp";
        }
        return "";
    }

    @Override
    public Class getColumnClass(int columnIndex) {
        //retorna a classe que representa a coluna
        if (columnIndex == COL_NOME) {
            return String.class;
        } else if (columnIndex == COL_QUANT) {
            return Integer.class;
        }
        return String.class;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        //pega o produto da linha
        Produto p = produtos.get(rowIndex);

        //verifica qual valor deve ser retornado
        if (columnIndex == COL_NOME) {
            return p.getNome();
        } else if (columnIndex == COL_QUANT) {
            return p.getQuant();
        }
        return "";
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //pega o produto da linha
        Produto p = produtos.get(rowIndex);

        //verifica qual valor vai ser alterado
        if (columnIndex == COL_NOME) {
            p.setNome(aValue.toString());
        } else if (columnIndex == COL_QUANT) {
            p.setQuant(Integer.parseInt(aValue.toString()));
        }

        //avisa que os dados mudaram
        fireTableDataChanged();
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        //no nosso caso todas vão ser editáveis, entao retorna true pra todas
        return true;
    }
        public void inserir(Produto p) {
        produtos.add(p);
 
        fireTableDataChanged();
    }
 
    public void excluir(int pos) {
        produtos.remove(pos);
 
        fireTableDataChanged();
    }
 
    public void excluir(Produto p) {
        produtos.remove(p);
 
        fireTableDataChanged();
    }
 
    public void ordenarPorNome() {
        //ordena pelo nome
        Collections.sort(produtos, new Comparator<Produto>() {
 
            public int compare(Produto o1, Produto o2) {
                return o1.getNome().compareTo(o2.getNome());
            }
        });
 
        //avisa que a tabela foi alterada
        fireTableDataChanged();
    }
 
    public void ordenarPorQuantidade() {
        //ordena pelo nome
        Collections.sort(produtos, new Comparator<Produto>() {
 
            public int compare(Produto o1, Produto o2) {
                return o1.getQuant() - o2.getQuant();
            }
        });
 
        //avisa que a tabela foi alterada
        fireTableDataChanged();
    }
 
    public void misturar() {
        //mistura a lista
        Collections.shuffle(produtos);
 
        //avisa que a tabela foi alterada
        fireTableDataChanged();
    }
 
   public Produto getCliente(int pos) {
        if (pos >= produtos.size()) {
            return null;
        }

        return produtos.get(pos);
    }
}

Para manipular os dados da tabela  é só manipular uma lista

Nos métodos de ordenação, em cada um deles é criado um objeto que implementa a interface Comparator que ordena de acordo com a necessidade: se é por ordem alfabética dos nomes, compara os nomes, se é pela quantidade em estoque, compara as quantidades.

OBS: Lembre sempre de chamar o método fireTableDataChanged() para avisar que os dados mudaram e a tabela ser redesenahda.

Voltando para aquela ideia de que esta tela seria uma tela de busca… possívelmente ela poderia ser chamada de uma outra tela (a de entrada de produtos por exemplo) para facilitar a busca de um produto. Como seria a recuperação do código do produto selecionado na tabela? Mais ou menos assim:


Arquivo JFTabela1.java


import java.util.ArrayList;
import java.util.Random;
import javax.swing.JOptionPane;


public class JFTabela1 extends javax.swing.JFrame {
   
     private ProdutoTableModel model;
    
      //variável só para controlar os códigos dos produtos
     private int ultimoCod;

    /**
     * Creates new form JFTabela1
     */
    public JFTabela1() {
        initComponents();
        ultimoCod = 1;

        //cria a lista com os produtos
        ArrayList<Produto> lista = new ArrayList<Produto>();
        lista.add(new Produto(ultimoCod++,"Caderno Universitário 200 f",5000));
        lista.add(new Produto(ultimoCod++,"Caderno Capa Dura 150 f",4000));
        lista.add(new Produto(ultimoCod++,"Caderno Caligrafia 100 f",1000));
        lista.add(new Produto(ultimoCod++,"Caderno Sem Pauta 200 f",1000));

        //cria o modelo de Produto
        model = new ProdutoTableModel(lista);

        //atribui o modelo à tabela
        jTable1.setModel(model);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */

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

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jButton4 = new javax.swing.JButton();
        jButton5 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        jTable1.setName("jTable1"); // NOI18N
        jScrollPane1.setViewportView(jTable1);

        jButton1.setText("INSERIR");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("EXCLUIR");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jButton3.setText("EMBARALHAR");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        jButton4.setText("CLASSIFICAR POR QUANTIDADE");
        jButton4.setActionCommand("jButton4");
        jButton4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton4ActionPerformed(evt);
            }
        });

        jButton5.setText("CLASSIFICAR POR NOME");
        jButton5.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton5ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jButton1, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jButton4, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jButton2)
                        .addGap(120, 120, 120)
                        .addComponent(jButton3))
                    .addComponent(jButton5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 211, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
         .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(193, 193, 193)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton1)
                    .addComponent(jButton2)
                    .addComponent(jButton3))
                .addGap(30, 30, 30)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton4)
                    .addComponent(jButton5))
                .addContainerGap(63, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                       

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {                                        
 model.misturar();        // TODO add your handling code here:
      
    }                                       

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
         Random r = new Random();
        Produto p = new Produto(ultimoCod++, "Produto "+String.valueOf(r.nextInt(100)), r.nextInt(1000));
        model.inserir(p);
    }                                       

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
         int selecionados[] = jTable1.getSelectedRows();
        if (selecionados.length > 0){
            ArrayList<Produto> seraoExcluidos = new ArrayList<Produto>();

            for (int i=0; i<selecionados.length; i++)
                seraoExcluidos.add(model.getCliente(selecionados[i]));

            for (Produto p : seraoExcluidos)
                model.excluir(p);           
        }else{
            JOptionPane.showMessageDialog(this, "Selecione alguém neh...");
        }
    }                                       

    private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {                                        
  model.ordenarPorQuantidade();        // TODO add your handling code here:
    }                                       

    private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {                                        
 model.ordenarPorNome();        // TODO add your handling code here:
    }                                       

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(JFTabela1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(JFTabela1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(JFTabela1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(JFTabela1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new JFTabela1().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                    
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JButton jButton4;
    private javax.swing.JButton jButton5;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration                  
}


run:

No construtor é criada uma lista com alguns produtos fictícios e também é instanciado o TableModel.

O botão inserir insere um produto com o nome “Produto i” e quantidade Q, onde ‘i’ e ‘Q’ são números randômicos.

O botão excluir trata a exclusão de vários ítens selecionados ao mesmo tempo. Primeiro todos são guardados em uma lista auxiliar e depois eles vão sendo excluídos um a um (Você sabe por que eu fiz assim? Pense um pouco… qualquer coisa a área de comentários está logo abaixo).


Os botões Ordenar por Nome, Ordenar por Quantidade e Misturar são auto explicativos e fazem exatamente o que o seu nome quer dizer.O que é o TableModel?