CellEditorListener will not detect when a cell has been edited
I am working on my CapStone project to graduate this semester, and have run into a few issues with the program I am working on.  The code is for the Serendipity Booksellers Program.  I am to design a Point-of-Sales system for a fictitious bookstore.

At the moment, I am stuck trying to get the "Total" column (column 5) to update when the user edits the "Qty" cell, for a given row.  The "Qty" field also needs to validate that it value in its cell is not greater than the quantity in stock (column 1).

I have also read [How to Use Tables](http://docs.oracle.com/javase/tutorial/uiswing/components/table.html) from the Java Tutorials, and searched Google for hours last night to try to find some helpful code on how to get CellEditorListener to work.

I have previously also tried having the CashierPanel class implement CellEditorListener, and register it by:

    CellEditorListener listener = null;
    table.getDefaultEditor(String.class).addCellEditorListener(listener);

This method did not work either.

Here is the code I have now (217 lines):


	/* Imported Dependencies */

	import java.awt.BorderLayout;
	import java.awt.Color;
	import java.awt.event.ActionEvent;
	import java.awt.event.ActionListener;
	import java.awt.event.KeyAdapter;
	import java.awt.event.KeyEvent;
	import java.math.BigDecimal;
	import java.math.RoundingMode;
	import java.util.ArrayList;

	import javax.swing.DefaultCellEditor;
	import javax.swing.JFrame;
	import javax.swing.JLabel;
	import javax.swing.JPanel;
	import javax.swing.JScrollPane;
	import javax.swing.JTable;
	import javax.swing.JTextField;
	import javax.swing.event.CellEditorListener;
	import javax.swing.event.ChangeEvent;
	import javax.swing.table.AbstractTableModel;
	import javax.swing.table.DefaultTableCellRenderer;
	import javax.swing.table.TableColumn;

	import net.miginfocom.swing.MigLayout;

	public class CashierPanel extends JFrame {

		/**
		* Serial Version UID
		*/
		private static final long serialVersionUID = 6922826100788686147L;

		/* Private Fields */
		private JPanel searchPanel;
		private JLabel isbn_lbl;
		private JLabel title_lbl;
		private JTextField isbn_tf;
		private JTextField title_tf;
		private JTextField currentCell;
		private BookCollection myCollection;
		private CashierTableModel tableData;

		private CellEditorListener listener;

		/**
		* Constructor
		*/
		public CashierPanel() {

			// Set window properties
			setTitle("Testing this FUCKING table");
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			setSize(585, 300);
			setLayout(new BorderLayout());

			tableData = new CashierTableModel();
			final JTable table = new JTable(tableData);
			table.setRowHeight(25);
			table.getTableHeader().setReorderingAllowed(false);
			table.setCellSelectionEnabled(true);
			table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
			add(new JScrollPane(table), BorderLayout.CENTER);

			// Define a cell renderer to render text to center of cell
			DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
			centerRenderer.setHorizontalAlignment(JLabel.CENTER);

			// Set column properties
			int[] sizes = new int[] { 50, 50, 87, 275, 50, 50 };
			String[] columnNames = new String[] { "Qty", "Stock", "ISBN", "Title",
					"Price", "Total" };
			TableColumn[] column = new TableColumn[columnNames.length];
			for (byte i = 0; i < columnNames.length; i++) {
				column[i] = table.getColumnModel().getColumn(i);
				column[i].setMinWidth(sizes[i]);
				column[i].setHeaderValue(columnNames[i]);
				if (i != 3) {
					column[i].setMaxWidth(sizes[i]);
					column[i].setCellRenderer(centerRenderer);
				}
			}

			/* Make the quantity field only display digits */
			currentCell = new JTextField();
			column[0].setCellEditor(new DefaultCellEditor(currentCell));
			// Add a key listener to the current cell
			currentCell.addKeyListener(new KeyAdapter() {
				public void keyTyped(KeyEvent e) {
					// if the key typed is not a digit or backspace
					if (!Character.isDigit(e.getKeyChar())
							&& e.getKeyChar() != KeyEvent.VK_BACK_SPACE) {
						currentCell.setEditable(false);
						currentCell.setBackground(Color.WHITE);
					} else {
						currentCell.setEditable(true);
					}
				}
			});

			/* Search panel */
			searchPanel = new JPanel();
			myCollection = new BookCollection();

			isbn_lbl = new JLabel("Search by ISBN:");
			isbn_tf = new JTextField();
			isbn_tf.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent event) {
					ArrayList<BookData> data = myCollection.select(isbn_tf.getText(), BookCollection.FIELD_ISBN);
					tableData.addNewRow();
					table.setValueAt((new BigDecimal("1").toString()), tableData.getRowCount() - 1, 0);
					table.setValueAt(Integer.toString(data.get(0).getQtyOnHand()), tableData.getRowCount() - 1, 1);
					table.setValueAt(data.get(0).getIsbn(),tableData.getRowCount() - 1, 2);
					table.setValueAt(data.get(0).getTitle(),tableData.getRowCount() - 1, 3);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount() - 1, 4);
					table.setValueAt(table.getValueAt(tableData.getRowCount() - 1, 4), tableData.getRowCount() - 1, 5);
					isbn_tf.setText("");
				}
			});

			title_lbl = new JLabel("Search by Title:");
			title_tf = new JTextField();
			title_tf.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent event) {
					ArrayList<BookData> data = myCollection.select(title_tf.getText(), BookCollection.FIELD_TITLE);
					tableData.addNewRow();
					table.setValueAt((new BigDecimal("1").toString()), tableData.getRowCount(), 0);
					table.setValueAt(Integer.toString(data.get(0).getQtyOnHand()), tableData.getRowCount() - 1, 1);
					table.setValueAt(data.get(0).getIsbn(), tableData.getRowCount(), 2);
					table.setValueAt(data.get(0).getTitle(), tableData.getRowCount(), 3);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount(), 4);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount(), 5);
					title_tf.setText("");
				}
			});

			searchPanel.setLayout(new MigLayout("", "[78px][202px,grow]", "[24px][29px]"));
			searchPanel.add(isbn_lbl, "cell 0 0, alignx left, aligny center");
			searchPanel.add(isbn_tf, "cell 1 0,growx, aligny center");
			searchPanel.add(title_lbl, "cell 0 1, alignx left, aligny center");
			searchPanel.add(title_tf, "cell 1 1, growx, aligny center");

			add(searchPanel, BorderLayout.SOUTH);

		};

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

	class CashierTableModel extends AbstractTableModel implements CellEditorListener{

		/**
	 	 * 
		 */
		private static final long serialVersionUID = -1500952132717353189L;
		private ArrayList<Object[]> data = new ArrayList<Object[]>();

		public void addNewRow() {
			data.add(new String[] { null, null, null, null, null, null });
			fireTableDataChanged();
		}

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

		public int getColumnCount() {
			return 6;
		}

		public Object getValueAt(int row, int col) {
			return data.get(row)[col];
		}

		public void setValueAt(Object value, int row, int col) {
			data.get(row)[col] = value;
			fireTableCellUpdated(row, col);
		}

		public boolean isCellEditable(int row, int col) {
			if (col > 0) {
				return false;
			} else {
				return true;
			}
		}

		public void editingCanceled(ChangeEvent e) {
			for (int i = 0; i <= getRowCount() - 1; i++) {
				BigDecimal[] data = new BigDecimal[3];
				data[0] = data[0].add((BigDecimal) getValueAt(i, 1));
				data[1] = data[1].add((BigDecimal) getValueAt(i, 4));
				data[2] = data[2].add(calculateTotal(data[0], data[1]));
				setValueAt(data[2], i, 5);
			}
		}

		public void editingStopped(ChangeEvent e) {
			for (int i = 0; i <= getRowCount() - 1; i++) {
				BigDecimal[] data = new BigDecimal[3];
				data[0] = data[0].add((BigDecimal) getValueAt(i, 1));
				data[1] = data[1].add((BigDecimal) getValueAt(i, 4));
				data[2] = data[2].add(calculateTotal(data[0], data[1]));
				setValueAt(data[2], i, 5);
			}
		}
	
		public BigDecimal calculateTotal(BigDecimal qty, BigDecimal retail) {
			BigDecimal total = new BigDecimal("0.00");
			total = total.add(qty.multiply(retail));
			return total;
		}
	}

As this is homework, I do not want to be handed a working version of my code, with the bugs worked out.  I would just like some guidance on what it is that I am doing wrong to get the editor listener to actually be called.

If there is any other information that I can provide that can help to guide me to a solution, please let me know.

Thanks for taking the time to look at this!
CellEditorListener will not detect when a cell has been edited
===

I am working on my CapStone project to graduate this semester, and have run into a few issues with the program I am working on.  The code is for the Serendipity Booksellers Program.  I am to design a Point-of-Sales system for a fictitious bookstore.

At the moment, I am stuck trying to get the "Total" column (column 5) to update when the user edits the "Qty" cell, for a given row.  The "Qty" field also needs to validate that it value in its cell is not greater than the quantity in stock (column 1).

I have also read [How to Use Tables](http://docs.oracle.com/javase/tutorial/uiswing/components/table.html) from the Java Tutorials, and searched Google for hours last night to try to find some helpful code on how to get CellEditorListener to work.

I have previously also tried having the CashierPanel class implement CellEditorListener, and register it by:

    CellEditorListener listener = null;
    table.getDefaultEditor(String.class).addCellEditorListener(listener);

This method did not work either.

Here is the code I have now (217 lines):


	/* Imported Dependencies */

	import java.awt.BorderLayout;
	import java.awt.Color;
	import java.awt.event.ActionEvent;
	import java.awt.event.ActionListener;
	import java.awt.event.KeyAdapter;
	import java.awt.event.KeyEvent;
	import java.math.BigDecimal;
	import java.math.RoundingMode;
	import java.util.ArrayList;

	import javax.swing.DefaultCellEditor;
	import javax.swing.JFrame;
	import javax.swing.JLabel;
	import javax.swing.JPanel;
	import javax.swing.JScrollPane;
	import javax.swing.JTable;
	import javax.swing.JTextField;
	import javax.swing.event.CellEditorListener;
	import javax.swing.event.ChangeEvent;
	import javax.swing.table.AbstractTableModel;
	import javax.swing.table.DefaultTableCellRenderer;
	import javax.swing.table.TableColumn;

	import net.miginfocom.swing.MigLayout;

	public class CashierPanel extends JFrame {

		/**
		* Serial Version UID
		*/
		private static final long serialVersionUID = 6922826100788686147L;

		/* Private Fields */
		private JPanel searchPanel;
		private JLabel isbn_lbl;
		private JLabel title_lbl;
		private JTextField isbn_tf;
		private JTextField title_tf;
		private JTextField currentCell;
		private BookCollection myCollection;
		private CashierTableModel tableData;

		private CellEditorListener listener;

		/**
		* Constructor
		*/
		public CashierPanel() {

			// Set window properties
			setTitle("Testing this FUCKING table");
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			setSize(585, 300);
			setLayout(new BorderLayout());

			tableData = new CashierTableModel();
			final JTable table = new JTable(tableData);
			table.setRowHeight(25);
			table.getTableHeader().setReorderingAllowed(false);
			table.setCellSelectionEnabled(true);
			table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
			add(new JScrollPane(table), BorderLayout.CENTER);

			// Define a cell renderer to render text to center of cell
			DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
			centerRenderer.setHorizontalAlignment(JLabel.CENTER);

			// Set column properties
			int[] sizes = new int[] { 50, 50, 87, 275, 50, 50 };
			String[] columnNames = new String[] { "Qty", "Stock", "ISBN", "Title",
					"Price", "Total" };
			TableColumn[] column = new TableColumn[columnNames.length];
			for (byte i = 0; i < columnNames.length; i++) {
				column[i] = table.getColumnModel().getColumn(i);
				column[i].setMinWidth(sizes[i]);
				column[i].setHeaderValue(columnNames[i]);
				if (i != 3) {
					column[i].setMaxWidth(sizes[i]);
					column[i].setCellRenderer(centerRenderer);
				}
			}

			/* Make the quantity field only display digits */
			currentCell = new JTextField();
			column[0].setCellEditor(new DefaultCellEditor(currentCell));
			// Add a key listener to the current cell
			currentCell.addKeyListener(new KeyAdapter() {
				public void keyTyped(KeyEvent e) {
					// if the key typed is not a digit or backspace
					if (!Character.isDigit(e.getKeyChar())
							&& e.getKeyChar() != KeyEvent.VK_BACK_SPACE) {
						currentCell.setEditable(false);
						currentCell.setBackground(Color.WHITE);
					} else {
						currentCell.setEditable(true);
					}
				}
			});

			/* Search panel */
			searchPanel = new JPanel();
			myCollection = new BookCollection();

			isbn_lbl = new JLabel("Search by ISBN:");
			isbn_tf = new JTextField();
			isbn_tf.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent event) {
					ArrayList<BookData> data = myCollection.select(isbn_tf.getText(), BookCollection.FIELD_ISBN);
					tableData.addNewRow();
					table.setValueAt((new BigDecimal("1").toString()), tableData.getRowCount() - 1, 0);
					table.setValueAt(Integer.toString(data.get(0).getQtyOnHand()), tableData.getRowCount() - 1, 1);
					table.setValueAt(data.get(0).getIsbn(),tableData.getRowCount() - 1, 2);
					table.setValueAt(data.get(0).getTitle(),tableData.getRowCount() - 1, 3);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount() - 1, 4);
					table.setValueAt(table.getValueAt(tableData.getRowCount() - 1, 4), tableData.getRowCount() - 1, 5);
					isbn_tf.setText("");
				}
			});

			title_lbl = new JLabel("Search by Title:");
			title_tf = new JTextField();
			title_tf.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent event) {
					ArrayList<BookData> data = myCollection.select(title_tf.getText(), BookCollection.FIELD_TITLE);
					tableData.addNewRow();
					table.setValueAt((new BigDecimal("1").toString()), tableData.getRowCount(), 0);
					table.setValueAt(Integer.toString(data.get(0).getQtyOnHand()), tableData.getRowCount() - 1, 1);
					table.setValueAt(data.get(0).getIsbn(), tableData.getRowCount(), 2);
					table.setValueAt(data.get(0).getTitle(), tableData.getRowCount(), 3);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount(), 4);
					table.setValueAt(data.get(0).getRetail().setScale(2, RoundingMode.HALF_UP).toString(), tableData.getRowCount(), 5);
					title_tf.setText("");
				}
			});

			searchPanel.setLayout(new MigLayout("", "[78px][202px,grow]", "[24px][29px]"));
			searchPanel.add(isbn_lbl, "cell 0 0, alignx left, aligny center");
			searchPanel.add(isbn_tf, "cell 1 0,growx, aligny center");
			searchPanel.add(title_lbl, "cell 0 1, alignx left, aligny center");
			searchPanel.add(title_tf, "cell 1 1, growx, aligny center");

			add(searchPanel, BorderLayout.SOUTH);

		};

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

	class CashierTableModel extends AbstractTableModel implements CellEditorListener{

		/**
	 	 * 
		 */
		private static final long serialVersionUID = -1500952132717353189L;
		private ArrayList<Object[]> data = new ArrayList<Object[]>();

		public void addNewRow() {
			data.add(new String[] { null, null, null, null, null, null });
			fireTableDataChanged();
		}

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

		public int getColumnCount() {
			return 6;
		}

		public Object getValueAt(int row, int col) {
			return data.get(row)[col];
		}

		public void setValueAt(Object value, int row, int col) {
			data.get(row)[col] = value;
			fireTableCellUpdated(row, col);
		}

		public boolean isCellEditable(int row, int col) {
			if (col > 0) {
				return false;
			} else {
				return true;
			}
		}

		public void editingCanceled(ChangeEvent e) {
			for (int i = 0; i <= getRowCount() - 1; i++) {
				BigDecimal[] data = new BigDecimal[3];
				data[0] = data[0].add((BigDecimal) getValueAt(i, 1));
				data[1] = data[1].add((BigDecimal) getValueAt(i, 4));
				data[2] = data[2].add(calculateTotal(data[0], data[1]));
				setValueAt(data[2], i, 5);
			}
		}

		public void editingStopped(ChangeEvent e) {
			for (int i = 0; i <= getRowCount() - 1; i++) {
				BigDecimal[] data = new BigDecimal[3];
				data[0] = data[0].add((BigDecimal) getValueAt(i, 1));
				data[1] = data[1].add((BigDecimal) getValueAt(i, 4));
				data[2] = data[2].add(calculateTotal(data[0], data[1]));
				setValueAt(data[2], i, 5);
			}
		}
	
		public BigDecimal calculateTotal(BigDecimal qty, BigDecimal retail) {
			BigDecimal total = new BigDecimal("0.00");
			total = total.add(qty.multiply(retail));
			return total;
		}
	}

As this is homework, I do not want to be handed a working version of my code, with the bugs worked out.  I would just like some guidance on what it is that I am doing wrong to get the editor listener to actually be called.

If there is any other information that I can provide that can help to guide me to a solution, please let me know.

Thanks for taking the time to look at this!