Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CellEditorListener will not detect when a cell has been edited

Tags:

java

swing

jtable

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 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 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!

like image 439
shattered.likeness Avatar asked Apr 21 '12 22:04

shattered.likeness


1 Answers

You are not supposed to add explicit key listeners to the cell editors by yourself and handle those events.

By default based on column type (if model returns cell as editable) the jtable will automatically choose appropriate editor. In case you need your own custom editor (for coloring etc) then also you need to implement it as cell editor and then just set it in column model.

Once you have editors installed in jtable whenever value is modified (may be triggered on focus lost) the jtable will automatically call setValueAt() of the model. All your logic of updating another dependent column should belong here.

like image 165
Ashwinee K Jha Avatar answered Oct 30 '22 12:10

Ashwinee K Jha