Inserting a row into a ResultTableModel as well as Database

痞子三分冷 提交于 2019-12-12 01:51:28

问题


I have a JTable that is populated from a database. I am using a custom model ResultSetTableModel. Below is the custom model:

public class ResultSetTableModel extends AbstractTableModel {
private String[] columnNames;
private Class[] columnClasses;
private List<List<Object>> cells = new ArrayList<List<Object>>();

public ResultSetTableModel() {
    columnNames = new String[1];
    columnNames[0] = "Result Set";

    List<Object> row = new ArrayList<Object>();
    row.add("No data");
    cells.add(row);
}

public ResultSetTableModel(ResultSet rs) throws SQLException {
    ResultSetMetaData rsmd = rs.getMetaData();

    // SOMETHING TO KEEP AN EYE ON! It looks like the ResultSetMetaData
    // object screws up once the ResultSet itself has been read (ie by
    // rs.next() ). Putting any rsmd.XXXX commands after the "while" loop at
    // the bottom throws a nasty exception. A bug on the SQLite side I
    // think.

    columnNames = new String[rsmd.getColumnCount()];
    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
        columnNames[i - 1] = rsmd.getColumnName(i);
    }

    columnClasses = new Class[rsmd.getColumnCount()];
    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
        int columnType = rsmd.getColumnType(i);

        switch (columnType) {
        case java.sql.Types.INTEGER:
        case java.sql.Types.NUMERIC:
            columnClasses[i - 1] = Integer.class;
            break;
        case java.sql.Types.VARCHAR:
        case java.sql.Types.CHAR:
        case java.sql.Types.DATE:
            columnClasses[i - 1] = String.class;
            break;
        case java.sql.Types.DECIMAL:
        case java.sql.Types.FLOAT:
            columnClasses[i - 1] = Float.class;
        default:
            columnClasses[i - 1] = Object.class;
            break;
        }
    }

    while (rs.next()) {
        List<Object> row = new ArrayList<Object>();
        for (int i = 1; i <= rsmd.getColumnCount(); i++) {
            row.add(rs.getString(i));
        }
        cells.add(row);
    }
}

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

public int getColumnCount() {
    return columnNames.length;
}

@Override
public Class getColumnClass(int columnIndex) {
    if (columnClasses != null) {
        return columnClasses[columnIndex];
    } else {
        return Object.class;
    }
}

public boolean isEmpty() {
    return cells.isEmpty();
}

public Object getValueAt(int rowIndex, int columnIndex) {
    return cells.get(rowIndex).get(columnIndex);
}

@Override
public String getColumnName(int columnIndex) {
    return columnNames[columnIndex];
}

public void deleteRowDisplay(int index) {
    this.cells.remove(index);
}

public void deleteRow(String username, String query, int indexOndisplay) {

    try {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager
                .getConnection("jdbc:mysql://localhost:3306/quotgen",
                        "root", "3498140591");
        Statement statement = connection.createStatement();
        statement.executeUpdate(query);

    } catch (ClassNotFoundException | SQLException e) {
        System.out.println(e.getMessage());
    }
    this.deleteRowDisplay(indexOndisplay);
    this.fireTableRowsDeleted(indexOndisplay, indexOndisplay);

   }
 }

My main class is as follows:

public class ControlP extends JFrame {

// variables
private static String query = "SELECT code as Code,description as Description, price as Price, quantity"
        + " as Quantity FROM products";
private JTable table;
private JScrollPane sp;
ResultSetTableModel rm;

JButton edit;
JButton add;

ControlP() {
    this.initUI();

    // button actions

    this.edit.addActionListener((ActionEvent) -> {

        JDialog editProduct = new JDialog(this,
                ModalityType.APPLICATION_MODAL);
        editProduct.setTitle("Edit Product");
        editProduct.setSize(400, 400);
        editProduct.setLayout(new java.awt.BorderLayout());
        editProduct.setLocationRelativeTo(this);

        final int selectedRow = this.table.getSelectedRow();
        EditProductRecord ap = new EditProductRecord(editProduct,
                this.table, selectedRow);
        editProduct.add(ap);
        editProduct.setVisible(true);
        editProduct.pack();

    });

}

private void initUI() {
    this.setSize(600, 600);
    this.setVisible(true);
    this.setLayout(new BorderLayout(5, 5));
    this.setLocationRelativeTo(null);
    edit = new JButton("Edit");
    add = new JButton("Add");

    this.add(edit, BorderLayout.NORTH);
    this.add(add, BorderLayout.SOUTH);

    // constructing the table here
    try {

        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager
                .getConnection("jdbc:mysql://localhost:3306/quotgen",
                        "root", "3498140591");
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery(query);
        this.rm = new ResultSetTableModel(result);
        this.table = new JTable(rm);
        if (!rm.isEmpty()) {
            table.setRowSelectionInterval(0, 0);
        }

        this.sp = new JScrollPane(this.table);
        this.add(sp, BorderLayout.CENTER);

    } catch (SQLException | ClassNotFoundException ex) {
        JOptionPane.showMessageDialog(null, ex.getMessage());
        // close connection
    }

}

public static void main(String[] args) {
    Runnable run = new Runnable() {

        @Override
        public void run() {
            ControlP cp = new ControlP();

        }

    };

    EventQueue.invokeLater(run);

   }
 }

Int this main class I have a button edit that when clicked will popup a JDialog containing a JPanel with details to update based on the highlighted row in the table. Here is the edit class:

public class EditProductRecord extends JPanel {
// JDBC driver name and database URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost/quotgen";

// Database credentials
static final String USER = "root";
static final String PASS = "3498140591";

public EditProductRecord(JDialog dialog, JTable table, int selectedRow) {
    this.initUI();

    // initialize panel fields
    this.codeT.setText((table.getValueAt(selectedRow, 0)).toString());
    this.descT.setText((table.getValueAt(selectedRow, 1)).toString());
    this.priceT.setText((table.getValueAt(selectedRow, 2)).toString());
    this.quantityT.setText((table.getValueAt(selectedRow, 3)).toString());
    this.codeT.setEnabled(false);
    this.codeT.setToolTipText("You cannot change the product code!");

    // /////////////////////////////////////////
    this.cancel.addActionListener((ActionEvent) -> {
        dialog.dispose();
    });

    this.save.addActionListener((ActionEvent) -> {

        // check that all input fields are not empty!
            if (this.descT.getText().equals("")
                    || this.priceT.getText().equals("")
                    || this.quantityT.getText().equals("")) {
                this.emptyField.setVisible(true);
            } else {

                Connection conn = null;
                Statement stmt = null;

                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    conn = DriverManager.getConnection(DB_URL, USER, PASS);
                    stmt = conn.createStatement();
                    String sql = "INSERT INTO products (code, description,price,quantity) "
                            + "VALUES ('"
                            + this.codeT.getText()
                            + "', '"
                            + this.descT.getText()
                            + "','"
                            + this.priceT.getText()
                            + "','"
                            + this.quantityT.getText()
                            + "')"
                            + "ON DUPLICATE KEY UPDATE description = '"
                            + this.descT.getText()
                            + "',price='"
                            + this.priceT.getText()
                            + "',quantity='"
                            + this.quantityT.getText() + "'";
                    stmt.execute(sql);

                    JOptionPane.showMessageDialog(dialog, "Done.");

                } catch (SQLException se) {
                    // Handle errors for JDBC
                    se.printStackTrace();
                } catch (Exception e) {
                    // Handle errors for Class.forName
                    e.printStackTrace();
                } finally {
                    // finally block used to close resources
                    try {
                        if (stmt != null)
                            conn.close();
                    } catch (SQLException se) {
                    }// do nothing
                    try {
                        if (conn != null)
                            conn.close();
                    } catch (SQLException se) {
                        se.printStackTrace();
                    }// end finally try
                }// end try
            }

        });
}

private void initUI() {
    // main panel properties
    this.setPreferredSize(new Dimension(400, 400));
    this.setLayout(new BorderLayout(5, 5));

    // dummy panels
    JPanel dummyN = new JPanel();
    dummyN.setPreferredSize(new Dimension(350, 50));

    JPanel dummyS = new JPanel();
    dummyS.setPreferredSize(new Dimension(350, 50));
    dummyS.setLayout(new net.miginfocom.swing.MigLayout());

    JPanel dummyE = new JPanel();
    dummyE.setPreferredSize(new Dimension(50, 300));

    JPanel dummyW = new JPanel();
    dummyW.setPreferredSize(new Dimension(50, 300));

    JPanel centerPanel = new JPanel();
    centerPanel.setPreferredSize(new Dimension(350, 300));
    centerPanel.setLayout(new net.miginfocom.swing.MigLayout());
    centerPanel.setBorder(BorderFactory.createTitledBorder("Product"));

    this.codeL = new JLabel("Code");
    this.codeT = new JTextField(10);
    this.descL = new JLabel("Description");
    ;
    this.descT = new JTextField(10);
    this.priceL = new JLabel("Price");
    ;
    this.priceT = new JTextField(10);
    this.quantityL = new JLabel("Quantity");
    ;
    this.quantityT = new JTextField(10);

    emptyField = new JLabel("All fields should have Input!");
    emptyField.setForeground(Color.red);
    emptyField.setVisible(false);

    centerPanel.add(this.codeL);
    centerPanel.add(this.codeT, "wrap");
    centerPanel.add(this.descL);
    centerPanel.add(this.descT, "wrap");
    centerPanel.add(this.priceL);
    centerPanel.add(this.priceT, "wrap");
    centerPanel.add(this.quantityL);
    centerPanel.add(this.quantityT, "wrap");
    centerPanel.add(emptyField);

    this.cancel = new JButton("Cancel");
    this.clear = new JButton("Clear");
    this.save = new JButton("Save");
    JLabel dummy = new JLabel("Dummy");
    dummy.setVisible(false);
    dummyS.add(dummy);
    dummyS.add(this.cancel);
    dummyS.add(this.clear);
    dummyS.add(this.save);

    this.add(centerPanel, BorderLayout.CENTER);
    this.add(dummyN, BorderLayout.NORTH);
    this.add(dummyS, BorderLayout.SOUTH);
    this.add(dummyW, BorderLayout.WEST);
    this.add(dummyE, BorderLayout.EAST);
}

// controls
JLabel codeL;
JTextField codeT;
JLabel descL;
JTextField descT;
JLabel priceL;
JTextField priceT;
JLabel quantityL;
JTextField quantityT;

JLabel emptyField;

JButton cancel;
JButton clear;
JButton save;

 }

Now everything is working fine except updating the data displayed in the table after saving the edited row.

Problem: When I click save to save my edits the data is sent to the database only and not in the table model.

I would want that after saving to the database the data is inserted into the model as well and this should be reflected on the display as well.

Question: How do we make it work the way I have suggested above? And Also how should the same happen after adding a row?

I have tried

    public void rowInserted(){
    this.fireTableDataChanged();
}

and call it after inserting into the database but it did not solve the problem.


回答1:


One method you might be able to use is to provide a means by which the you can "update" the TableModel from the database, including only those rows which have changed.

This would require you to know the "key" or "id" of the row(s) inserted/updated and run a select query only for those values. You would then pass this ResultSet to the pre-existing TableModel via some kind of "update" method, which would simply load or update the rows from the ResultSet.

This may require have some kind of Map which is keyed to the "key" or "id" of the row, so you can update it more easily.

One of things I might consider is providing an POJO of the row data, which you can use to not only store in you look up Map, but also discover the model's row index for the specified record.



来源:https://stackoverflow.com/questions/29577125/inserting-a-row-into-a-resulttablemodel-as-well-as-database

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!