0

My goal is to be able to edit a JTable cell that, once edited and saved, saves the value into the database and loads the value onto the JTable. Currently, once I try to edit a JTable cell and press enter, the data does not get saved. I have realized that the TableModelListener is not being called; the system.out code in the actualizeTable model is not working.

The following code is for the Frame; I have taken out some codes (namely the JButton ActionListeners) as they are deemed unnecessary for this topic.

public class InventoryFrame extends JFrame{
    DatabaseManager dbman;
    private JPanel p  = new JPanel();
    private final JButton getAll = new JButton("Get All");
    private final JButton add = new JButton("Add");
    private final JButton delete = new JButton("Delete");
    private final JButton edit = new JButton("Edit");
    
    private ResultSet rs;
    
    private JTable jt;
    public InventoryFrame() throws Exception {
        // TODO Auto-generated constructor stub
        super();
        setTitle("Inventory");
        setSize(800,600);
        p.setLayout(new BorderLayout());
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        isResizable();
        
        getContentPane().add(p);
        p.add(getAll, BorderLayout.NORTH);
        dbman = new DatabaseManager();
        if(null == rs) {
            rs = dbman.getAllQuery();
        }
        InventoryTableModel itm = new InventoryTableModel(rs);
        getAll.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                jt = new JTable(itm);
                jt.setColumnSelectionAllowed(true);
                jt.setRowSelectionAllowed(true);
                
                /*if (jt.getCellEditor() != null) {
                    jt.getCellEditor().stopCellEditing();
                }*/
                
                JScrollPane sp = new JScrollPane(jt);
                p.add(sp, BorderLayout.CENTER);
                pack();
                setSize(800,600);
                doLayout();
                
            }
        });
        itm.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                // TODO Auto-generated method stub
                actualizeTable(e);
            }
        });
    public void actualizeTable(TableModelEvent e) {
        System.out.println("entering editing..."+e.getType()+", "+TableModelEvent.UPDATE);
        if ((int) e.getType() == TableModelEvent.UPDATE) {
            System.out.println("editing...");
            InventoryTableModel model = (InventoryTableModel) ((TableModel) e.getSource());
            int row = e.getFirstRow();
            int column = e.getColumn();
            String input = String.valueOf(model.getValueAt(jt.getSelectedRow(), jt.getSelectedColumn()));
            dbman.update(column, input);
            model.setValueAt(input, row, column);
            
            pack();
            setSize(800,600);
            doLayout();
        }
    }
}

Here is my InventoryTableModel class:

public class InventoryTableModel extends AbstractTableModel {
    private ResultSet rset;
    private int rowCount = 0;
    private int columnCnt=0;
    private String columnName = "";
    public InventoryTableModel(ResultSet rs){
        // TODO Auto-generated constructor stub
        rset = rs;
        
        try {
            if(rset.last()) {
                rowCount = rset.getRow();
            }
            columnCnt = rset.getMetaData().getColumnCount();
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
            
    }

    @Override
    public int getColumnCount() {
        return columnCnt;
    }

    @Override
    public int getRowCount() {
        return rowCount;
    }
    @Override
    public Object getValueAt(int row, int col) {
        // TODO Auto-generated method stub
        try {
            if(!rset.absolute(row+1)) {
                return null;
            }
            Object value = rset.getObject(col +1);
            //System.out.println("value is: "+value);
            return value;
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    public boolean isCellEditable(int row, int col) {
        return true;
    }
    public String getColumnName(int col) {
        try {
            String colName = rset.getMetaData().getColumnName(col+1);
            if (colName.equals("ProductID")) {
                return "Product ID";
            } else if (colName.equals("ProductName")){
                return "Product Name";
            } else if (colName.equals("DateAdded")) {
                return "Date Added";
            }
            return colName;
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "";
    }
}

This is the update() method that is called and parts of the DatabaseManager class:

public DatabaseManager() throws Exception {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            // Setup the connection with the DB
            connection = DriverManager
                    .getConnection("jdbc:mysql://localhost:3306/inventory", username, password);
            statement = connection.createStatement();
            System.out.println("Successfully Connected");
        } catch (Exception e) {
            throw e;
        
    }

    }
    public ResultSet getAllQuery() {
        try {
            resultSet = statement.executeQuery("select * from inventory");
        } catch (Exception e){
            e.printStackTrace();
        }
        return resultSet;
    }
    public void update(int col, String input) {
        String colName = "";
        if (col == 1) {
            colName = "ProductID";
        } else if (col == 2) {
            colName = "ProductName";
        } else if (col == 3) {
            colName = "Price";
        } else if (col == 4) {
            colName = "Quantity";
        } else if (col == 5) {
            colName = "Description";
        } else if (col == 6) {
            colName = "Category";
        } else if (col == 7) {
            colName = "DateAdded";
        }
        try {
            String query = "UPDATE INVENTORY "
                    + "SET "+colName+ "= ?"
                    + " WHERE PRODUCTID = ?";
            pstatement = connection.prepareStatement(query);
            
            pstatement.setString(1, input);
            pstatement.setInt(2, col);
            
            pstatement.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Any help would be appreciated!

1 Answers1

1

My goal is to be able to edit a JTable cell that, once edited and saved, saves the value into the database and loads the value onto the JTable.

Your understanding of the JTable and/or TableModelListener is incorrect.

When you edit a cell in the JTable, the data will be stored in the TableModel via the setValueAt(...) method. The setValueAt() method will then invoke the TableModelListener to indicate that a change to the TableModel has occured.

You don't get the TableModelEvent because your TableModel doesn't implement the setValueAt(...) method.

I would suggest there is no need for you to create a custom TableModel. Instead, copy the data from your ResultSet to the DefaultTableModel and then use the DefaultTableModel in your JTable.

The DefaultTableModel does implement setValueAt(...). So when you edit the JTable, the data will be saved to the TableModel and the TableModelEvent will be generated. In the TableModelListener you can then update your database.

Check out: How to get a DefaultTableModel object's data into a subclass of DefaultTableModel for an example that shows how to generically load data from a ResultSet to the DefaultTableModel.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • So I have added and coded the setValueAt method for the TableModel. However, my main problem is that the TabelModelListener is never getting called, even when I double-click a cell, change the value, and press enter. The data value goes back to its original value and nothing gets updated. How do you fix this? – Grant Hu Aug 14 '20 at 21:22
  • @GrantHu, *the TabelModelListener is never getting called* - You haven't implemented the setValueAt(). method correctly. it is the responsibility of the `TableModel` to generate the `TableModelEvent`. Read the section from the Swing tutorial on [Creating a TableModel](https://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data) for an example on how to do this. I still maintain there is no reason for the custom TableModel. *The data value goes back to its original value* - the setValueAt() method is not implemented correctly or you have another logic error. – camickr Aug 14 '20 at 23:18
  • I've already explained to you how most people work with a JTable and a database. Its simpler and less error prone. Good luck. – camickr Aug 14 '20 at 23:21