title: Add & Delete Row for JTable of Custom Components
body: <p>I'm doing step by step...</p>
  
  <p><a href="https://stackoverflow.com/questions/44319428/changing-lookandfeel-of-jtable-of-custom-component">Changing LookAndFeel of JTable of Custom Component</a></p>
  
  <p><strong>Note</strong>: <em>I have more custom Columns, this code it's for demonstration porpoise.</em></p>
  
  <p>Now, I want to implement add Row and Delete Row using a class extended from <code>DefaultTableModel</code>, for <code>JTable</code> populated with custom Objects.</p>
  
  <p>Here my code:</p>
  
  <pre><code>import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;
  import javax.swing.table.*;
  
  public class LAF_TableCustom_AddDelRow {
  
    static JFrame frame = new JFrame();
  
    public JComponent makeUI() {
  
      String[] hdrsObjects = {"PanelSpinnerRadioButton Class Column"};
      Object[][] objectMatrix = new Object[3][1];
      objectMatrix[0][0] = new PanelSpinnerRadioButtonData(false, 10, 40);
      objectMatrix[1][0] = new PanelSpinnerRadioButtonData(true,  20, 40);
      objectMatrix[2][0] = new PanelSpinnerRadioButtonData(false, 30, 40);
  
  //    JTable table = new JTable(new DefaultTableModel(objectMatrix, hdrsObjects)) {
      JTable table = new JTable(new PSRBTableModel(objectMatrix, hdrsObjects)) {
        @Override public void updateUI() {
          super.updateUI();
          setRowHeight(30);
          TableColumn tc = getColumn("PanelSpinnerRadioButton Class Column");
          tc.setCellRenderer(new PSRBTableCellRenderer());
          tc.setCellEditor(new PSRBTableCellEditor());
        }
      };
  
      JScrollPane scrollPane = new JScrollPane(table);
      scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
      scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
  
      JPanel pV = new JPanel();
      pV.setLayout(new BoxLayout(pV, BoxLayout.PAGE_AXIS));
  
      JButton bAddRow = new JButton("Add Row");
      bAddRow.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent evt) {
          ((PSRBTableModel)table.getModel()).addRow(
              new Object[] { new PanelSpinnerRadioButtonData(false, 10, 40) }
          );
  //        ((DefaultTableModel)table.getModel()).addRow(
  //            new Object[] { new PanelSpinnerRadioButtonData(false, 10, 40) }
  //        );
        }
      });
  
      pV.add(bAddRow);
      pV.add(scrollPane);
      return pV;
    }
  
    public static void main(String... args) {
      EventQueue.invokeLater(() -&gt; {
      frame.getContentPane().add(new LAF_TableCustom_AddDelRow().makeUI());
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      frame.setSize(320, 240);
      frame.setVisible(true);
      });
    }
  
  }
  
  class PanelSpinnerRadioButtonData {
    private boolean opt02 = false;
    private Integer from = 0;
    private Integer size = 1;
  
    PanelSpinnerRadioButtonData() {
      this(false, 5, 10);
    }
    PanelSpinnerRadioButtonData(boolean opt02, Integer from, Integer size) {
      this.opt02 = opt02;
      this.from = from;
      this.size = size;
    }
    public boolean getOption() {
      return opt02;
    }
    public Integer getFrom() {
      return from;
    }
    public Integer getSize() {
      return size;
    }
  }
  
  class PanelSpinnerRadioButton extends JPanel {
    public final JRadioButton jrbOption01 = new JRadioButton("01");
    public final JRadioButton jrbOption02 = new JRadioButton("12");
    public final JSpinner jspnValues = new JSpinner(new SpinnerNumberModel(5, 0, 10, 1));
    public final JButton jbRemoveRow = new JButton("Del Row");
  
    private final JPanel panel = new JPanel();
  
    PanelSpinnerRadioButton() {
      this(new PanelSpinnerRadioButtonData(false, 20, 40));
    }
    PanelSpinnerRadioButton(PanelSpinnerRadioButtonData data) {
      super();
  
      panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
      panel.add(jrbOption01);
      panel.add(jrbOption02);
      panel.add(jspnValues);
      panel.add(jbRemoveRow);
  
      jbRemoveRow.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
          JTable table = (JTable)SwingUtilities.getAncestorOfClass(
              JTable.class, (Component) e.getSource());
          int row = table.getEditingRow();
          table.getCellEditor().stopCellEditing();
  //        ((DefaultTableModel) table.getModel()).removeRow(row);
          ((PSRBTableModel) table.getModel()).removeRow(row);
  
        }
      });
  
      ButtonGroup bg = new ButtonGroup();
      bg.add(jrbOption01);
      bg.add(jrbOption02);
      ((SpinnerNumberModel) jspnValues.getModel()).setMaximum(data.getSize());
      setData(data);
  
      init();
    }
    private void init() {
      setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
      setBackground(new Color(0, 0, 0, 0));
      add(panel);
    }
    public void setData(PanelSpinnerRadioButtonData data) {
      if (data.getOption()) {
        jrbOption02.setSelected(true);
      } else {
        jrbOption01.setSelected(true);
      }
      ((SpinnerNumberModel) jspnValues.getModel()).setValue(data.getFrom());
    }
    public PanelSpinnerRadioButtonData getData() {
      return new PanelSpinnerRadioButtonData(
          jrbOption02.isSelected(),
          (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getValue(),
          (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getMaximum());
    }
  
  }
  
  class PSRBTableCellRenderer implements TableCellRenderer {
    private final PanelSpinnerRadioButton renderer = new PanelSpinnerRadioButton();
    @Override public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
      if (value instanceof PanelSpinnerRadioButtonData) {
        renderer.setData((PanelSpinnerRadioButtonData) value);
      }
      return renderer;
    }
  }
  
  class PSRBTableCellEditor extends AbstractCellEditor implements TableCellEditor {
    private final PanelSpinnerRadioButton editor = new PanelSpinnerRadioButton();
    @Override public Object getCellEditorValue() {
      return editor.getData();
    }
    @Override public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column) {
      if (value instanceof PanelSpinnerRadioButtonData) {
        editor.setData((PanelSpinnerRadioButtonData) value);
      }
      return editor;
    }
  
  }
  
  //class PSRBTableModel extends AbstractTableModel {
  class PSRBTableModel extends DefaultTableModel {
  
    private final Object[][] data;
    private final Object[] columns;
  
    public PSRBTableModel(Object[][] data, Object[] columns) {
      this.data = data;
      this.columns = columns;
    }
  
    @Override public Object getValueAt(int rowIndex, int columnIndex) {
      if (data != null) {
        if (data.length &gt; 0) {
          return data[rowIndex][columnIndex];
        }
      }
      return null;
    }
  
    @Override public int getColumnCount() {
      return ((columns == null) ? 0: columns.length);
    }
  
    @Override public int getRowCount() {
      return ((data == null) ? 0: data.length);
    }
  
    @Override public Class getColumnClass(int columnIndex) {
      if (data != null) {
        if (data.length &gt; 0) {
          if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
            return PanelSpinnerRadioButton.class;
          }
          return data[0][columnIndex].getClass();
        }
      }
      return Object.class;
    }
  
    @Override public boolean isCellEditable(int rowIndex, int columnIndex) {
      if (data != null) {
        if (data.length &gt; 0) {
          if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
            return true;
          }
        }
      }
      return true;
    }
  
    @Override public void setValueAt(Object value, int row, int col) {
      data[row][col] = value;
      fireTableCellUpdated(row, col);
    }
  
    @Override public String getColumnName(int columnIndex) {
      return (String)columns[columnIndex];
    }
  
    @Override public void removeRow(int row) {
      fireTableRowsDeleted(row, row);
      System.out.println("fireTableRowsDeleted(" + row + ", " + row + ");");
    }
  
    @Override public void addRow(Object[] rowData) {
      super.addRow(rowData);
    }
  }
  </code></pre>
  
  <p>The problem!!!</p>
  
  <p>When I pressed the <code>Del Row</code> Button, the row wasn't deleted!
  I got the print message related with the Row: <code>fireTableRowsDeleted(ROW, ROW);</code>I </p>
  
  <p>When I pressed the <code>Add Row</code> I got this Exception...</p>
  
  <pre><code>Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 3 &gt; 0
      at java.util.Vector.insertElementAt(Vector.java:598)
      at javax.swing.table.DefaultTableModel.insertRow(DefaultTableModel.java:374)
      at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:350)
      at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:361)
      at PSRBTableModel.addRow(LAF_TableCustom_AddDelRow.java:248)
      at LAF_TableCustom_AddDelRow$2.actionPerformed(LAF_TableCustom_AddDelRow.java:45)
      at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
  </code></pre>
  
  <p>How Can I to do these operations (removeRow, addRow), overriding respective methods with my Custom <code>DefaultTableModel</code>?</p>
  
  <p>This <a href="https://stackoverflow.com/questions/13880545/remove-rows-from-jtable-with-abstracttablemodel">answer</a>, is not working </p>
  
  <p><strong>EDIT</strong> </p>
  
  <pre><code>  //Doesn't Work
    @Override public void removeRow(int row) {
      super.removeRow(row);
    }
  
    //Doesn't Work
    @Override public void removeRow(int row) {
      getDataVector().removeElementAt(row);
      fireTableRowsDeleted(row, row);
    }
  
    //Doesn't Work (Not overriding the Method)
    //  @Override public void removeRow(int row) {
    //    getDataVector().removeElementAt(row);
    //  }
  </code></pre>