Como adicionar checkbox em JTable? ( não é default)

Salve amigos do GUJ.
Sou programador iniciante e estou tentando implementar uma Jtable em uma aplicação que estou desenvolvendo. Já procurei vários exemplos na internet e até aqui no fórum , porém ainda não consegui implementar o que preciso.

   Meu problema é o seguinte:
   A cada clique no botão que tenho na aplicação gerada pelos códigos abaixo eu gero uma nova linha na tabela.
  preciso de um checkbox em todas as linhas para que quando o usuário desejar utilizar os valores contidos nestas linhas eu possa resgatar quais foram selecionadas.

  Abaixo coloco o código rápido  que criei de exemplo para que quem souber me ajudar ajuste para me mostrar como se faz. O código a seguir gera um painel com uma Jtable e um botão que  tem apenas o objetivo de adicionar linhas à tabela e quando solucionar este problema ele será substituído por uma thread e esta alimentará a tabela de acordo com dados obtidos de um banco de dados.

Obrigado desde já.

//ESSA É A CLASSE MAIN

import telasFiscal.InterfaceFiscal;

public class Main {

public static void main(String args[]) {
    InterfaceFiscal p = new InterfaceFiscal();

    p.setLocationRelativeTo(null);
    p.setVisible(true);
}

}

//FIM DA CLASSE MAIN

//ESSA É A TELA ONDE TENHO A TABELA E O BOTAO DE ADICIONAR LINHAS

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;

public class InterfaceFiscal extends javax.swing.JFrame {
int contador;

public ModeloTabelaFiscal modeloTabelaLista = new ModeloTabelaFiscal();

public InterfaceFiscal() {

    setResizable(false);
    setBounds(0, 0, 1200, 750);
    initComponents();

}

private void initComponents() {
    setTitle("INTERFACE");

    addWindowListener(new java.awt.event.WindowAdapter() {
        public void windowClosing(java.awt.event.WindowEvent evt) {

            setDefaultCloseOperation(EXIT_ON_CLOSE);

        }
    });

    painelJanela = new javax.swing.JPanel();
    painelJanela.setBackground(new Color(21, 82, 137));
    painelJanela.setLayout(null);

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

    tableListaDePlacas = new JTable(modeloTabelaLista);
    tableListaDePlacas.setBounds(59, 291, 694, 267);

    tableListaDePlacas.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

    tableListaDePlacas.setRowHeight(17);

    tableListaDePlacas.getColumnModel().getColumn(0).setPreferredWidth(100);
    tableListaDePlacas.getColumnModel().getColumn(1).setPreferredWidth(80);
    tableListaDePlacas.getColumnModel().getColumn(2).setPreferredWidth(80);
    tableListaDePlacas.getColumnModel().getColumn(3).setPreferredWidth(60);
    tableListaDePlacas.getColumnModel().getColumn(4).setPreferredWidth(70);
    tableListaDePlacas.getColumnModel().getColumn(5).setPreferredWidth(300);
    tableListaDePlacas.getColumnModel().getColumn(6).setPreferredWidth(70);
    tableListaDePlacas.getColumnModel().getColumn(7).setPreferredWidth(70);
    tableListaDePlacas.getColumnModel().getColumn(8).setPreferredWidth(326);

    tableListaDePlacas.setDefaultRenderer(Object.class, new FormataTabelaFiscal());
    modeloTabelaLista.addTableModelListener(tableListaDePlacas);

    scrollPane = new JScrollPane();
    scrollPane.setAutoscrolls(true);
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPane.setBounds(10, 79, 1174, 635);
    scrollPane.setViewportView(tableListaDePlacas);
    painelJanela.add(scrollPane);

    JButton btnNewButton_1 = new JButton("ADICIONAR LINHA");
    btnNewButton_1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            contador++;

            String exemplo = Integer.toString(contador);
            RegistrosMonitorFiscal u = new RegistrosMonitorFiscal();

            u.setId("checkbox aqui");
            u.setNfe(exemplo);
            u.setCnpj(exemplo);
            u.setCodsap(exemplo);
            u.setDescricao(exemplo);
            u.setPlaca(exemplo);
            u.setHoraentrada(exemplo);
            u.setStatus(exemplo);

            modeloTabelaLista.addRegistros(u);

        }
    });
    btnNewButton_1.setBounds(10, 11, 248, 57);
    painelJanela.add(btnNewButton_1);

}

private javax.swing.JPanel painelJanela;
private JSeparator separator_2;
public Object actionListenerDaClasse;
@SuppressWarnings("unused")
private JButton btnNewButton;
JTable tableListaDePlacas;
private JScrollPane scrollPane;
private JTextArea textArea;

}
//FIM DA TELA ONDE TENHO A TABELA E O BOTAO DE ADICIONAR LINHAS

//CLASSE MODELO DA MINHA TABELA

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

import javax.swing.table.AbstractTableModel;

public class ModeloTabelaFiscal extends AbstractTableModel {

private List<RegistrosMonitorFiscal> Registross;
private String[] colunas = new String[] { "ID", "TESTE", "TESTE", "TESTE", "TESTE", "TESTE", "TESTE", "TESTE",
        "TESTE" };

public ModeloTabelaFiscal(List<RegistrosMonitorFiscal> Registross) {
    this.Registross = Registross;
}

public ModeloTabelaFiscal() {
    this.Registross = new ArrayList<RegistrosMonitorFiscal>();
}

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

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

@Override
public String getColumnName(int columnIndex) {
    return colunas[columnIndex];
}

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

public void setValueAt(RegistrosMonitorFiscal aValue, int rowIndex) {
    RegistrosMonitorFiscal Registros = Registross.get(rowIndex);

    Registros.setId(aValue.getId());
    Registros.setId(aValue.getRemessa());
    Registros.setNfe(aValue.getNfe());
    Registros.setCnpj(aValue.getCnpj());
    Registros.setCodsap(aValue.getCodsap());
    Registros.setDescricao(aValue.getDescricao());
    Registros.setPlaca(aValue.getPlaca());
    Registros.setHoraentrada(aValue.getHoraentrada());
    Registros.setStatus(aValue.getStatus());

    fireTableCellUpdated(rowIndex, 0);
    fireTableCellUpdated(rowIndex, 1);
    fireTableCellUpdated(rowIndex, 2);
    fireTableCellUpdated(rowIndex, 3);
    fireTableCellUpdated(rowIndex, 4);
    fireTableCellUpdated(rowIndex, 5);
    fireTableCellUpdated(rowIndex, 6);
    fireTableCellUpdated(rowIndex, 7);
    fireTableCellUpdated(rowIndex, 8);
}

public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    RegistrosMonitorFiscal Registros = Registross.get(rowIndex);

    switch (columnIndex) {
    case 0:

        Registros.setId(aValue.toString());

    case 1:

        Registros.setRemessa(aValue.toString());

    case 2:

        Registros.setNfe(aValue.toString());
    case 3:

        Registros.setCnpj(aValue.toString());
    case 4:

        Registros.setCodsap(aValue.toString());
    case 5:

        Registros.setDescricao(aValue.toString());
    case 6:

        Registros.setPlaca(aValue.toString());
    case 7:

        Registros.setHoraentrada(aValue.toString());
    case 8:

        Registros.setStatus(aValue.toString());

    default:

        System.err.println("Índice da coluna inválido");
    }
    fireTableCellUpdated(rowIndex, columnIndex);
}

public Object getValueAt(int rowIndex, int columnIndex) {
    RegistrosMonitorFiscal RegistrosSelecionado = Registross.get(rowIndex);
    String valueObject = null;
    switch (columnIndex) {

    case 0:
        valueObject = RegistrosSelecionado.getId();
        break;

    case 1:
        valueObject = RegistrosSelecionado.getRemessa();
        break;

    case 2:
        valueObject = RegistrosSelecionado.getNfe();
        break;
    case 3:
        valueObject = RegistrosSelecionado.getCnpj();
        break;
    case 4:
        valueObject = RegistrosSelecionado.getCodsap();
        break;
    case 5:
        valueObject = RegistrosSelecionado.getDescricao();
        break;
    case 6:
        valueObject = RegistrosSelecionado.getPlaca();
        break;
    case 7:
        valueObject = RegistrosSelecionado.getHoraentrada();
        break;
    case 8:
        valueObject = RegistrosSelecionado.getStatus();
        break;

    default:
        System.err.println("Índice inválido para propriedade do bean Registros.class");
    }

    return valueObject;
}

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

public RegistrosMonitorFiscal getRegistros(int indiceLinha) {
    return Registross.get(indiceLinha);
}

public void addRegistros(RegistrosMonitorFiscal u) {
    Registross.add(u);

    int ultimoIndice = getRowCount() - 1;

    fireTableRowsInserted(ultimoIndice, ultimoIndice);
}

public void removeRegistros(int indiceLinha) {
    Registross.remove(indiceLinha);

    fireTableRowsDeleted(indiceLinha, indiceLinha);
}

public void addListaDeRegistross(List<RegistrosMonitorFiscal> novosRegistross) {

    int tamanhoAntigo = getRowCount();
    Registross.addAll(novosRegistross);
    fireTableRowsInserted(tamanhoAntigo, getRowCount() - 1);
}

public void limpar() {
    Registross.clear();
    fireTableDataChanged();
}

public boolean isEmpty() {
    return Registross.isEmpty();
}

}

//FIM DO MODELO DA TABELA

//STRINGS GETS e SETS

public class RegistrosMonitorFiscal {

private String id;
private String mov;
private String remessa;
private String nfe;
private String codsap;
private String descricao;
private String horaentrada;
private String status;
private String cnpj;
private String placa;

public String getCnpj() {
    return cnpj;
}

public void setCnpj(String cnpj) {
    this.cnpj = cnpj;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getNfe() {
    return nfe;
}

public void setNfe(String nfe) {
    this.nfe = nfe;
}

public String getCodsap() {
    return codsap;
}

public void setCodsap(String codsap) {
    this.codsap = codsap;
}

public String getDescricao() {
    return descricao;
}

public void setDescricao(String descricao) {
    this.descricao = descricao;
}

public String getHoraentrada() {
    return horaentrada;
}

public void setHoraentrada(String horaentrada) {
    this.horaentrada = horaentrada;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

public String getPlaca() {
    return placa;
}

public void setPlaca(String placa) {
    this.placa = placa;
}

public String getMov() {
    return mov;
}

public void setMov(String mov) {
    this.mov = mov;
}

public String getRemessa() {
    return remessa;
}

public void setRemessa(String remessa) {
    this.remessa = remessa;
}

}
//FIM STRINGS

//CLASSE CELLRENDER

import java.awt.Component;

import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

public class FormataTabelaFiscal extends DefaultTableCellRenderer {

public Component getTableCellRendererComponent(JTable tabelaFiscal, Object value, boolean isSelected,
        boolean hasFocus, int row, int column) {
    Component celulas = super.getTableCellRendererComponent(tabelaFiscal, value, isSelected, hasFocus, row, column);

    return celulas;

}

}

Cara, pelo JTable dá para você selecionar linhas por padrão, não é necessário checkboxes, além disso, é padrão que você possa selecionar várias linhas usando o ctrl,

ai você pode pegar as linhas com o comando

DefaultTableModel modelo=suatabela.getModel();
modelo.getSelectedRows();

e fazer um for pra pegar todos os valores das linhas selecionadas acima

Primeiramente obrigado pela resposta Thomasbrazpinto, porém o problema é que serão muitas linhas e na seleção com o ctrl se o usuario der um clic errado perde toda a seleção que fez.

tenta usar esse codigo:

suaTabela.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

    Valew Thomas ....
    Então este modo de seleção já funcionava por default. e até atendia mas imagine a seguinte hipótese:
    minha tabela tem um painel onde cabem somente 10 linhas para visualizar sem rolar a barra e tenho 40 linhas na tabela sendo que preciso selecionar as 10 primeiras , a trigésima e a ultima linha além de ter que rolar a barra lateral tenho que cuidar para não clicar no lugar errado senão perco toda a seleção e neste caso o checkbox seria a melhor opção pois ele só perde a seleção se o usuário clicar em cima da caixa do checkbox.

bom, nesse caso, você vai ter duas opções, ou dar uma pesquisada melhor nesse método que eu te falei, para deixar tipo quando clicasse em uma, nao “desselecionasse” as outras, eu não sei qual é o comando, mas existe.

a segunda opção é você fazer um AbstractTableModel e adicionar uma nova coluna à tabela, com o tipo da coluna setado em “boolean”, dá uma lida nisso aqui, é em inglês mas é só jogar no tradutor:

https://docs.oracle.com/javase/tutorial/uiswing/components/table.html

no tópico Concepts: Editors and Renderers ele fala:

types:
Boolean — rendered with a check box.//o que te interessa, "renderizado com um checkbox"
Number — rendered by a right-aligned label.
Double, Float — same as Number, but the object-to-text translation is performed by a NumberFormat instance (using the default number format for the current locale).
Date — rendered by a label, with the object-to-text translation performed by a DateFormat instance (using a short style for the date and time).
ImageIcon, Icon — rendered by a centered label.
Object — rendered by a label that displays the object's string value.

Boolean: rendered with checkbox

tradução: renderizado com um checkbox, ou seja se você setar o tipo da coluna para boolean, você renderiza um checkbox

ainda não consegui,pois não entendi como adicionar o check box na tabela.mas mesmo assim obrigado pela ajuda.

não sei se já conseguiu, mas dê uma olhada nesse tópico, tem me ajudado muito ultimamente