title: An Interactive JTable
body: <p>I am developing a simple Java Application that uses a JTable. I am trying to implement what I have seen <a href="http://www.javalobby.org/articles/jtable/index.jsp" rel="nofollow">here</a>. The table on the link given has behavior exactly the  same as what I want in my table. I have done exactly as what is shown on the referenced link. <strong>However, when I run my application I am not able to edit the third and last column.</strong>
  <strong>The behavior that I want is that the application should add an empty row when the user press Enter upon filling the last column in the table.</strong></p>
  
  <p>Here is my first class, the entity class:</p>
  
  <pre><code>public class Product {
  String productDescription;
  String productCode;
  double productPrice;
  //dummy properties
  int productQuantity;
  double productTotalAmount;
  
   public Product() {
      this.productDescription = "";
      this.productCode = "";
      this.productPrice = 0;
      this.productTotalAmount = 0;
      this.productQuantity = 0;
  }
  
  public int getProductQuantity() {
      return productQuantity;
  }
  
  public void setProductQuantity(int productQuantity) {
      this.productQuantity = productQuantity;
  }
  
  public double getProductTotalAmount() {
      return productTotalAmount;
  }
  
  public void setProductTotalAmount(double productTotalAmount) {
      this.productTotalAmount = productTotalAmount;
  }
  
  public String getProductDescription() {
      return productDescription;
  }
  
  public void setProductDescription(String productDescription) {
      this.productDescription = productDescription;
  }
  
  public String getProductCode() {
      return productCode;
  }
  
  public void setProductCode(String productCode) {
      this.productCode = productCode;
  }
  
  public double getProductPrice() {
      return productPrice;
  }
  
  public void setProductPrice(double productPrice) {
      this.productPrice = productPrice;
  }}
  </code></pre>
  
  <p>Here is my second class, the table model:</p>
  
  <pre><code>public class InteractiveTableModel extends AbstractTableModel{
  
  // indexes
   public static final int PRODUCT_DESCRIPTION_INDEX = 0;
   public static final int PRODUCT_CODE_INDEX = 1;
   public static final int PRODUCT_PRICE_INDEX = 2;
   public static final int PRODUCT_QUANTITY_INDEX=3;
   public static final int PRODUCT_TOTAL_AMOUNT_INDEX=4;
   public static final int HIDDEN_INDEX = 5;
  
   protected String [] columnNames;
   protected Vector dataVector;
  
    //this constructor is responsible for initializing the columnmanes and the data of the table.
   public InteractiveTableModel(String[] columnNames) {
       this.columnNames = columnNames;
       dataVector = new Vector();
   }
  
  
  @Override
   //this method returns the name of the column corresponding to the passed integer.
   public String getColumnName(int column) {
       return columnNames[column];
   }
  
    //this method is used to determine whether a cell is editable
   //this is for manuvouring to the next editable cell
   @Override
  
   public boolean isCellEditable(int row, int column) {
       if (column == HIDDEN_INDEX) return false;
       else return true;
   }
  
   @Override
        public Class getColumnClass(int column) {// returns a class representing the datatype of the data stored in that column
       switch (column) {
           case PRODUCT_DESCRIPTION_INDEX:
           case PRODUCT_CODE_INDEX:
              return String.class;
           case PRODUCT_QUANTITY_INDEX:
               return Integer.class;
           case PRODUCT_PRICE_INDEX:
           case PRODUCT_TOTAL_AMOUNT_INDEX:
               return double.class;
           default:
              return Object.class;
       }
   }
  
  @Override
  public int getRowCount() {
          return dataVector.size();
  }
  
  @Override
  public int getColumnCount() {
  return columnNames.length;
  }
  
   @Override
   public Object getValueAt(int row, int column) {
       Product record = (Product)dataVector.get(row);//this will return a row in a vector
       //this is cast to AudioRecord so that we can extract the data that we want correspoinding to column number
       switch (column) {
           case PRODUCT_DESCRIPTION_INDEX:
              return record.getProductDescription();
           case PRODUCT_CODE_INDEX:
              return record.getProductCode();
           case PRODUCT_PRICE_INDEX:
              return record.getProductPrice();
           case PRODUCT_TOTAL_AMOUNT_INDEX:
              return record.getProductTotalAmount();
          case PRODUCT_QUANTITY_INDEX:
              return record.getProductQuantity();
           default:
              return new Object();
       }
   }
  
        //setting data in a cell
   @Override
   public void setValueAt(Object value, int row, int column) {
       Product record = (Product)dataVector.get(row);
       switch (column) {
           case PRODUCT_DESCRIPTION_INDEX:
              record.setProductDescription((String)value);
              break;
           case PRODUCT_CODE_INDEX:
              record.setProductCode((String)value);
              break;
           case PRODUCT_PRICE_INDEX:
              record.setProductPrice((Double)value);
              break;
           case PRODUCT_QUANTITY_INDEX:
              record.setProductQuantity((Integer)value);
               break;
             case PRODUCT_TOTAL_AMOUNT_INDEX:
              record.setProductTotalAmount((Double)value);
                 break;
           default:
              System.out.println("invalid index");
       }
       fireTableCellUpdated(row, column);//this is for updating the cell
   }
  
  
   public boolean hasEmptyRow() {
       if (dataVector.isEmpty()) return false;
       Product productRecord = (Product)dataVector.get(dataVector.size() - 1);
       if (productRecord.getProductDescription().trim().equals("") &amp;&amp;
          productRecord.getProductCode().trim().equals("") &amp;&amp;
          (productRecord.getProductPrice()!=1 &amp;&amp;
           productRecord.getProductQuantity()!=1 &amp;&amp;
            productRecord.getProductTotalAmount()!=1))
       {
          return true;
       }
       else return false;
   }
  
   public void addEmptyRow() {
       dataVector.add(new Product());
       fireTableRowsInserted(
          dataVector.size() - 1,
          dataVector.size() - 1);
   }}
  </code></pre>
  
  <p>The last class is as follows:</p>
  
  <pre><code> public final class InteractiveForm extends JPanel {
  
   public static final String[] columnNames = {
       "Quantity", "Product Code", "Product Description", "Product Price","Product Quantity",""
   };
  
   protected JTable table;
   protected JScrollPane scroller;
   protected InteractiveTableModel tableModel;
  
   public InteractiveForm() {
       initComponent();
   }
  
   public void initComponent() {
       tableModel = new InteractiveTableModel(columnNames);
       tableModel.addTableModelListener(new InteractiveForm.InteractiveTableModelListener());
       table = new JTable();
       table.setModel(tableModel);
       table.setSurrendersFocusOnKeystroke(true);
       if (!tableModel.hasEmptyRow()) {
           tableModel.addEmptyRow();
       }
  
       scroller = new javax.swing.JScrollPane(table);
       table.setPreferredScrollableViewportSize(new java.awt.Dimension(500, 300));
       TableColumn hidden = table.getColumnModel().getColumn(InteractiveTableModel.HIDDEN_INDEX);
       hidden.setMinWidth(2);
       hidden.setPreferredWidth(2);
       hidden.setMaxWidth(2);
       hidden.setCellRenderer(new InteractiveRenderer(InteractiveTableModel.HIDDEN_INDEX));
  
       setLayout(new BorderLayout());
       add(scroller, BorderLayout.CENTER);
   }
  
  
   public void highlightLastRow(int row) {
       int lastrow = tableModel.getRowCount();//return the number of rows - last row
       if (row == lastrow - 1) {
           table.setRowSelectionInterval(lastrow - 1, lastrow - 1);
       } else {
           table.setRowSelectionInterval(row + 1, row + 1);
       }
  
       table.setColumnSelectionInterval(0, 0);//setting it to the first column
   }
  
   class InteractiveRenderer extends DefaultTableCellRenderer {
       protected int interactiveColumn;
  
       public InteractiveRenderer(int interactiveColumn) {
           this.interactiveColumn = interactiveColumn;
       }
  
       @Override
       public Component getTableCellRendererComponent(JTable table,
          Object value, boolean isSelected, boolean hasFocus, int row,
          int column)
       {
           Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
           if (column == interactiveColumn &amp;&amp; hasFocus) {
               if ((InteractiveForm.this.tableModel.getRowCount() - 1) == row &amp;&amp;
                  !InteractiveForm.this.tableModel.hasEmptyRow())
               {
                   InteractiveForm.this.tableModel.addEmptyRow();//this is where we append a new row
               }
  
               highlightLastRow(row);//making it get focus and highlighted
           }
  
           return c;//returning the component
       }
   }
  
   public class InteractiveTableModelListener implements TableModelListener {
       @Override
       public void tableChanged(TableModelEvent evt) {
           if (evt.getType() == TableModelEvent.UPDATE) {
               int column = evt.getColumn();
               int row = evt.getFirstRow();
               System.out.println("row: " + row + " column: " + column);
               table.setColumnSelectionInterval(column + 1, column + 1);
               table.setRowSelectionInterval(row, row);
           }
       }
   }
  
   public static void main(String[] args) {
       try {
           UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
           JFrame frame = new JFrame("Interactive Form");
           frame.addWindowListener(new WindowAdapter() {
               @Override
               public void windowClosing(WindowEvent evt) {
                   System.exit(0);
               }
           });
           frame.getContentPane().add(new InteractiveForm());
           frame.pack();
           frame.setVisible(true);
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException | HeadlessException e) {
       }
   }}
  </code></pre>
  
  <p>The only differences that I have made from the table on the link above is to add my own variables of which that should not make it not work.The logic is escaping me here.</p>
  
  <p>How can I make my table behave the same way as <a href="http://www.javalobby.org/articles/jtable/index.jsp" rel="nofollow">this one</a>?</p>