我有一个使用ResultSet& AbstractTableModel
由Access DB填充的JTable。我有一个方法可以正确地从DB中删除记录,但是在刷新表模型的当前视图时遇到问题。我查看了类似的帖子,并尝试使用fireTableRowsDeleted
和fireTableDataChanged
,但没有运气。我还注意到其他帖子提到DefaultTableModel
的使用,因为它添加/删除行方法,但我工作的代码来自我去年使用过的Java教科书(教授从未达到过这一点,所以我试过自己学习)...
这是自定义JFrame的类:
class AdministrationFrame extends JFrame
{
//set variable for location of database
private static final File DB_FILE =
new File("C:\\Eclipse\\EmpInOutBoard - TEMP.accdb");
//database URL
private static final String DB_URL = "jdbc:ucanaccess://" + DB_FILE.getAbsolutePath();
//set default query to retrieve all users sorted by last name
private static final String DEFAULT_QUERY =
"SELECT EmployeeNo, FirstName, LastName, DisplayName, GroupName, CompanyName "
+ "FROM Employees "
+ "WHERE DisabledState = false "
+ "ORDER BY LastName";
//layout for window
private final BorderLayout layout;
//administration window
private final JFrame adminFrame;
private final JPanel tablePanel;
private final JPanel tablePanel2;
private final JPanel buttonPanel;
//items for tablePanel
private final JLabel filterLabel;
private final JTextField filterTextField;
private final JButton filterButton;
//items for buttonPanel
private final JButton updateButton;
private final JButton deleteButton;
private String employeeID;
private Connection conn;
private JTable resultTable;
private static ResultSetTableModel tblModel;
public AdministrationFrame()
{
layout = new BorderLayout(10, 10);
setLayout(layout);
//place GUI components on JFrame's content pane
adminFrame = new JFrame("Employee Modification Panel");
//set up JPanels
tablePanel = new JPanel();
tablePanel2 = new JPanel();
String tablePanelTitle = "Employee Details";
tablePanel.setBorder(BorderFactory.createTitledBorder(null,
tablePanelTitle, TitledBorder.CENTER, TitledBorder.TOP,
new Font("Arial", Font.BOLD + Font.ITALIC, 22), Color.BLACK));
tablePanel2.setLayout(new BoxLayout(tablePanel2, BoxLayout.Y_AXIS));
buttonPanel = new JPanel();
//set up items in each JPanel
filterLabel = new JLabel("Filter:");
filterLabel.setAlignmentX(LEFT_ALIGNMENT);
filterTextField = new JTextField();
filterTextField.setAlignmentX(LEFT_ALIGNMENT);
filterButton = new JButton("Apply Filter");
filterButton.setAlignmentX(LEFT_ALIGNMENT);
updateButton = new JButton("Add/Update");
deleteButton = new JButton("Delete");
//create ResultSetTableModel and display database table
try
{
//create TableModel for results of the default query
tblModel = new ResultSetTableModel(DB_URL, DEFAULT_QUERY);
//create JTable based on the tblModel
resultTable = new JTable(tblModel)
{
@Override
public Dimension getPreferredScrollableViewportSize()
{
return new Dimension(600, 250);
}
};
resultTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
resultTable.getTableHeader().setResizingAllowed(false); //disable column resizing
resultTable.getTableHeader().setReorderingAllowed(false); //disable column dragging
resultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //sets table to only allow selection of single row
resultTable.getSelectionModel().addListSelectionListener(new RowListener()); //register event handlers
final JScrollPane tablePane = new JScrollPane(resultTable);
//add items to JPanels
tablePanel2.add(filterLabel);
tablePanel2.add(Box.createRigidArea(new Dimension(0, 2)));
tablePanel2.add(filterTextField);
tablePanel2.add(Box.createRigidArea(new Dimension(0, 10)));
tablePanel2.add(filterButton);
tablePanel.add(tablePane);
tablePanel.add(tablePanel2);
buttonPanel.add(updateButton);
buttonPanel.add(deleteButton);
//add JPanels to frame
adminFrame.add(tablePanel, BorderLayout.NORTH);
adminFrame.add(buttonPanel, BorderLayout.SOUTH);
final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tblModel);
resultTable.setRowSorter(sorter);
//create listener for filterButton
filterButton.addActionListener(new ActionListener()
{
//pass filter text to Listener
public void actionPerformed(ActionEvent e)
{
String text = filterTextField.getText();
if (text.length() == 0)
sorter.setRowFilter(null);
else
{
try
{
//make filter case-insensitive
sorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
catch (PatternSyntaxException pse)
{
JOptionPane.showMessageDialog(null, "Bad regex pattern",
"Bad regex pattern", JOptionPane.ERROR_MESSAGE);
}
}
}
});
deleteButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
if(employeeID != null && !employeeID.isEmpty())
{
try
{
deleteFromTable(employeeID);
JOptionPane.showMessageDialog(null, "User " + employeeID + " deleted from the table",
"Successful Deletion", JOptionPane.PLAIN_MESSAGE);
//tblModel.fireTableRowsDeleted(resultTable.getSelectedRow(), resultTable.getSelectedRow());
}
catch (SQLException e1)
{
e1.printStackTrace();
}
}
else
{
JOptionPane.showMessageDialog(null, "No user selected. Cannot perform delete.",
"ERROR", JOptionPane.ERROR_MESSAGE);
}
}
});
pack();
//dispose of window when user quits application
//(do not want to close application)
adminFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
adminFrame.setSize(800, 400);
adminFrame.setVisible(true);
adminFrame.setLocationRelativeTo(null);
adminFrame.setResizable(false);
//ensure database is closed when user quits application
adminFrame.addWindowListener(new WindowAdapter()
{
//disconnect from database and exit when window has closed
public void windowClosed(WindowEvent event)
{
tblModel.disconnectFromDatabase();
System.exit(0);
}
});
}
catch (SQLException sqlException)
{
JOptionPane.showMessageDialog(null, sqlException.getMessage(),
"Database error", JOptionPane.ERROR_MESSAGE);
tblModel.disconnectFromDatabase();
System.exit(1); //terminate application
}
}
private class RowListener implements ListSelectionListener
{
@Override
public void valueChanged(ListSelectionEvent event)
{
if(!event.getValueIsAdjusting())
{
int row = resultTable.getSelectedRow();
if(row == -1) //no row found
JOptionPane.showMessageDialog(adminFrame, "Selected row not found in filtered set",
null, JOptionPane.WARNING_MESSAGE);
else
{
employeeID = resultTable.getValueAt(row, resultTable.getColumn("EmployeeNo").getModelIndex()).toString();
}
}
}
};
//updates DB to delete selected user/record from the table
public void deleteFromTable(String empID) throws SQLException
{
PreparedStatement prepStmnt = null;
String deleteSQL = "DELETE "
+ "FROM Employees "
+ "WHERE EmployeeNo = ?";
try
{
conn = DriverManager.getConnection(DB_URL);
conn.setAutoCommit(false);
prepStmnt = conn.prepareStatement(deleteSQL);
prepStmnt.setString(1, empID);
prepStmnt.executeUpdate();
conn.commit();
}
catch (SQLException sqlExcep)
{
sqlExcep.printStackTrace();
if(conn != null)
{
try
{
System.err.print("Rolling back transaction");
conn.rollback();
}
catch (SQLException excep)
{
excep.printStackTrace();
}
}
System.exit(1); //terminate application
}
finally //close the connection
{
if(prepStmnt != null)
prepStmnt.close();
conn.setAutoCommit(true);
conn.close();
}
}
}//end class EmpInOutBoard
&#13;
这里是AbstractTableModel的类(从我的教科书中略微修改):
class ResultSetTableModel extends AbstractTableModel
{
private final Connection connection;
private final Statement statement;
private ResultSet resultSet;
private ResultSetMetaData resultSetMetaData;
private int numRowCount;
//track DB connection status
private boolean dbConnStatus = false;
//constructor initializes rSet and obtains its
//metadata object; also determines number of rows
public ResultSetTableModel(String url, String query) throws SQLException
{
//connect to the database
connection = DriverManager.getConnection(url);
//create statement to query database
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
//update database connection status
dbConnStatus = true;
//set query and execute it
setQuery(query);
}
//get class that represents column type
@SuppressWarnings({ "unchecked", "rawtypes" })
public Class getColumnClass(int column) throws IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
//determine Java class of column
try
{
String className = resultSetMetaData.getColumnClassName(column + 1);
//return Class object that represents class Name
return Class.forName(className);
}
catch (Exception e)
{
e.printStackTrace();
}
return Object.class; //if problems occur above, assume type Object
}
//remove row in the ResultSet
public void removeRow(int row)
{
// try
// {
// resultSet.absolute(row);
// resultSet.deleteRow();
// }
// catch (SQLException e)
// {
// e.printStackTrace();
// }
// fireTableRowsDeleted(row, row);
}
//get the number of columns in the ResultSet
public int getColumnCount() throws IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
//determine number of columns
try
{
return resultSetMetaData.getColumnCount();
}
catch (SQLException sqlException)
{
sqlException.printStackTrace();
}
return 0; //if problem occur above, return 0 for number of columns
}
//get name of a particular column in ResultSet
public String getColumnName(int column) throws IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
//determine column name
try
{
return resultSetMetaData.getColumnName(column + 1);
}
catch (SQLException sqlException)
{
sqlException.printStackTrace();
}
return ""; //if problems occur above, return empty string for column name
}
//return number of rows in ResultSet
public int getRowCount() throws IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
return numRowCount;
}
//obtain value in particular row and column
public Object getValueAt(int row, int column) throws IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
//obtain a value at specified ResultSet row and column
try
{
resultSet.absolute(row + 1);
return resultSet.getObject(column + 1);
}
catch (SQLException sqlException)
{
sqlException.printStackTrace();
}
return ""; //if problems occur above, return empty string object
}
//set new database query string
public void setQuery(String query) throws SQLException, IllegalStateException
{
//ensure database connection is available
if(!dbConnStatus)
throw new IllegalStateException("No connection to the Database");
//specify query and execute it
resultSet = statement.executeQuery(query);
//obtain metadata for ResultSet
resultSetMetaData = resultSet.getMetaData();
//determine number of rows in ResultSet
resultSet.last(); //move to last row
numRowCount = resultSet.getRow(); //get row number
//notify JTable that model has changed
fireTableStructureChanged();
}
//close Statement and Connection
public void disconnectFromDatabase()
{
//ensure database connection is available
if(dbConnStatus);
//determine number of columns
try
{
resultSet.close();
statement.close();
connection.close();
}
catch (SQLException sqlException)
{
sqlException.printStackTrace();
}
finally
{
dbConnStatus = false;
}
}
} //end class ResultSetTableModel
&#13;
正如您所看到的,我已尝试在第二个类中添加removeRow方法但最终收到错误:attempt to assign to non-updatable column
。刷新我的桌子模型我缺少什么?我愿意将此更改为使用DefaultTableModel
及其内置方法,如果这更容易/更简单。感谢
答案 0 :(得分:0)
我没有使用直接行索引,因为如果用户按任意一列对数据进行排序,则可能会发生变化。我觉得,既然employeeID是独一无二的,那就更好地匹配:
//remove row in the ResultSet
public void removeRow(String empID)
{
int rsRow = 0;
try
{
//set cursor to beginning of data set (before first row)
if(!resultSet.isBeforeFirst())
resultSet.beforeFirst();
//iterate through resultSet to find matching record with
//correct employee ID. once found delete row
while(resultSet.next())
{
if(resultSet.getString("EmployeeNo") == empID)
{
rsRow = resultSet.getRow();
resultSet.deleteRow();
System.out.println("User: " + empID + " was deleted from row: " + rsRow);
break;
}
}
resultSet.last();
numRowCount = resultSet.getRow();
fireTableRowsDeleted(rsRow, rsRow);
// resultSet.absolute(rsRow);
// resultSet.deleteRow();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
&#13;
当然,现在JTable中的数据正在消失,我不明白。