我正在使用连接到MySQL数据库的Swing应用程序。它从数据库中获取一些数据并显示在表中。此外,还有3个按钮,用于更改表数据(添加行到表),更新数据库(更新数据库)和丢弃更改(放弃更改),如下所示,
单击向表中添加行按钮后,表单中的新条目应添加到表中。之后,如果单击更新按钮,数据将在db中更新。放弃更改将删除表的最后一行中的数据,并且与db无关。该应用程序有两个类 CoffeesFrame.java 和 CoffeesTableModel.java 我提供了以下两个类的示例代码,
public class CoffeesFrame extends JFrame implements RowSetListener {
private static final long serialVersionUID = 1L;
private static Connection myConn = null;
private static String url = "jdbc:mysql://localhost:3306/myDemo";
private static String user = "student";
private static String password = "student";
// initiate a table object
JTable table;
// labels of the table
// text data fields of the table
// buttons of the table
// initiate a table model object
CoffeesTableModel myCoffeesTableModel;
// table constructor
public CoffeesFrame(Connection myConn) throws SQLException {
table = new JTable();
createNewTableModel(myConn);
/*
label, text field and buttons
*/
Container contentPane = getContentPane();
contentPane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
/*
Code for making the GUI
*/
button_ADD_ROW.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// showMessageDialog works
JOptionPane.showMessageDialog(CoffeesFrame.this, new String[] {
"Adding the following row:",
"Coffee name: [" + textField_COF_NAME.getText() + "]",
"Supplier ID: [" + textField_SUP_ID.getText() + "]",
"Price: [" + textField_PRICE.getText() + "]",
"Sales: [" + textField_SALES.getText() + "]",
"Total: [" + textField_TOTAL.getText() + "]" });
try {
// Insert row is not adding data to the table
myCoffeesTableModel.insertRow(
textField_COF_NAME.getText(),
Integer.parseInt(textField_SUP_ID.getText().trim()),
Float.parseFloat(textField_PRICE.getText().trim()),
Integer.parseInt(textField_SALES.getText().trim()),
Integer.parseInt(textField_TOTAL.getText().trim()));
// table.getModel();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
});
button_UPDATE_DATABASE.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
myCoffeesTableModel.coffeesRowSet.acceptChanges(myConn);
}
catch (Exception ex) {
ex.printStackTrace();
}
try {
createNewTableModel(myConn);
}
catch (Exception el) {
el.printStackTrace();
}
}
});
button_DISCARD_CHANGES.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("The changes are DISCARDED");
}
});
}
private void createNewTableModel(Connection myConn) throws SQLException {
myCoffeesTableModel = new CoffeesTableModel(getContentsOfCoffeesTable(myConn));
myCoffeesTableModel.addEventHandlersToRowSet(this);
table.setModel(myCoffeesTableModel);
}
@Override
public void rowSetChanged(RowSetEvent event) {
// TODO Auto-generated method stub
}
@Override
public void rowChanged(RowSetEvent event) {
// TODO Auto-generated method stub
}
@Override
public void cursorMoved(RowSetEvent event) {
// TODO Auto-generated method stub
}
public CachedRowSet getContentsOfCoffeesTable(Connection mycConn)
throws SQLException {
CachedRowSet crs = null;
ResultSet resultSet = null;
Statement stmt = null;
String sql = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
try {
stmt = myConn.createStatement();
resultSet = stmt.executeQuery(sql);
crs = new CachedRowSetImpl();
crs.populate(resultSet);
}
catch (Exception e) {
e.printStackTrace();
}
return crs;
}
public static void main(String[] args) throws SQLException {
try {
myConn = DriverManager.getConnection(url, user, password);
if (myConn != null) {
System.out.println("Connected to the database myDemo");
}
}
catch (SQLException ex) {
System.out
.println("An error occurred. Maybe user/password is invalid");
ex.printStackTrace();
}
myConn.setAutoCommit(false);
CoffeesFrame coffeesFrame = new CoffeesFrame(myConn);
coffeesFrame.pack();
coffeesFrame.setVisible(true);
}
}
CoffeesTableModel.java如下,//
public class CoffeesTableModel implements TableModel {
CachedRowSet coffeesRowSet; // The ResultSet to interpret
ResultSetMetaData metadata; // Additional information about the results
int numcols, numrows; // How many rows and columns in the table
public CoffeesTableModel(CachedRowSet rowSetArg) throws SQLException {
this.coffeesRowSet = rowSetArg;
this.metadata = this.coffeesRowSet.getMetaData();
numcols = metadata.getColumnCount();
// Retrieve the number of rows.
this.coffeesRowSet.beforeFirst();
this.numrows = 0;
while (this.coffeesRowSet.next()) {
this.numrows++;
}
this.coffeesRowSet.beforeFirst();
}
public CachedRowSet getCoffeesRowSet() {
return coffeesRowSet;
}
public void addEventHandlersToRowSet(RowSetListener listener) {
this.coffeesRowSet.addRowSetListener(listener);
}
public void insertRow(String coffeeName, int supplierID, float price,
int sales, int total) throws SQLException {
try {
this.coffeesRowSet.moveToInsertRow();
this.coffeesRowSet.updateString("COF_NAME", coffeeName);
this.coffeesRowSet.updateInt("SUP_ID", supplierID);
this.coffeesRowSet.updateFloat("PRICE", price);
this.coffeesRowSet.updateInt("SALES", sales);
this.coffeesRowSet.updateInt("TOTAL", total);
this.coffeesRowSet.insertRow();
this.coffeesRowSet.moveToCurrentRow();
}
catch (SQLException e) {
e.printStackTrace();
// JDBCTutorialUtilities.printSQLException(e);
}
}
public void close() {
try {
coffeesRowSet.getStatement().close();
}
catch (SQLException e) {
e.printStackTrace();
// JDBCTutorialUtilities.printSQLException(e);
}
}
/** Automatically close when we're garbage collected */
protected void finalize() {
close();
}
/** Method from interface TableModel; returns the number of columns */
public int getColumnCount() {
return numcols;
}
/** Method from interface TableModel; returns the number of rows */
public int getRowCount() {
return numrows;
}
/**
* Method from interface TableModel; returns the column name at columnIndex
* based on information from ResultSetMetaData
*/
public String getColumnName(int column) {
try {
return this.metadata.getColumnLabel(column + 1);
}
catch (SQLException e) {
return e.toString();
}
}
/**
* Method from interface TableModel; returns the most specific superclass
* for all cell values in the specified column. To keep things simple, all
* data in the table are converted to String objects; hence, this method
* returns the String class.
*/
public Class getColumnClass(int column) {
return String.class;
}
/**
* Method from interface TableModel; returns the value for the cell
* specified by columnIndex and rowIndex. TableModel uses this method to
* populate itself with data from the row set. SQL starts numbering its rows
* and columns at 1, but TableModel starts at 0.
*/
public Object getValueAt(int rowIndex, int columnIndex) {
try {
this.coffeesRowSet.absolute(rowIndex + 1);
Object o = this.coffeesRowSet.getObject(columnIndex + 1);
if (o == null)
return null;
else
return o.toString();
}
catch (SQLException e) {
return e.toString();
}
}
/**
* Method from interface TableModel; returns true if the specified cell is
* editable. This sample does not allow users to edit any cells from the
* TableModel (rows are added by another window control). Thus, this method
* returns false.
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
// Because the sample does not allow users to edit any cells from the
// TableModel, the following methods, setValueAt, addTableModelListener,
// and removeTableModelListener, do not need to be implemented.
public void setValueAt(Object value, int row, int column) {
System.out.println("Calling setValueAt row " + row + ", column "
+ column);
}
public void addTableModelListener(TableModelListener l) {
}
public void removeTableModelListener(TableModelListener l) {
}
}
表中显示的数据从数据库中获取并显示为表。 "添加行到表"显示表单插入的弹出窗口,但不要将数据作为新行放在表格的末尾。但是,我没有收到任何错误。 "更新数据库"按钮不起作用并提供 java.sql.SQLException:未指定表。。我该如何改进代码?
答案 0 :(得分:3)
您应该从TableModel
扩展而不是实现AbstractTableModel
接口,而是具有某些" normal"的默认功能。您不想复制的功能。
删除addTableModelListener
和removeTableModelListener
,您当前的实施基本上违反了模型的合同,因为它无法向其他观察者发送通知(例如JTable
)
您的insertRow
方法必须致电fireTableRowsInserted
(来自AbstractTableModel
),以便通知JTable
模型已更改,并且需要使用新版本更新自己数据
Java不保证finalize
将被调用,不依赖它
getRowCount
将受RowSet
的大小影响,因此,您需要能够保持运行值(即,您需要在添加新行时增加它)或计算RowSet
本身的行数。我相信你可以通过将光标移动到末尾(或超出最后位置)并使用getRow
来做到这一点,不要忘记,ResultSet
是基于1
的,不是基于0
期望
JTable