当前位置: 首页 > 知识库问答 >
问题:

在删除或插入后更新JTable

咸昊昊
2023-03-14

我有一个由Access DB使用ResultSet&AbstractTableModel填充的JTable。我有一个方法可以正确地从数据库中删除记录,但在刷新表模型的当前视图时遇到了困难。我看过类似的帖子,并尝试使用FireTableRowsDeletedFireTableDataChanged,但没有成功。我还注意到其他帖子提到了DefaultTableModel的使用,因为它有add/remove行方法,但我使用的代码来自我去年使用的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

下面是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

正如您所看到的,我试图在第二个类中添加一个removeRow方法,但最终得到一个错误:尝试赋值给不可更新的列。刷新表模型缺少什么?如果这样更容易/更简单,我愿意将其更改为使用DefaultTableModel及其内置方法。谢谢

共有1个答案

勾起运
2023-03-14

我没有使用直接行索引,因为如果用户按任一列对数据进行排序,则该索引可能会改变。我认为,由于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();
		}
	}
	
 类似资料:
  • 插入、更新和删除语句基于以开头的层次结构生成 UpdateBase . 这个 Insert 和 Update 构建基于中介的 ValuesBase . DML基础构造函数 顶级的“插入”、“更新”、“删除”构造函数。 Object Name Description delete(table[, whereclause, bind, returning, ...], **dialect_kw) 构建

  • 问题内容: 我只是对某事感到好奇。让我说我有一个表,我将更新该值,然后将其删除,然后插入新的1。如果我以这种方式编写代码,这将非常容易: 但是,如果使用“ update”语句,它将更加容易。但我的问题是,有可能同时完成这3个步骤吗? 问题答案: 引用Oracle事务处理语句文档: 事务是一个逻辑的 原子工作单元 ,包含一个或多个SQL语句。事务对SQL语句进行分组,以使它们要么全部提交(这意味着它

  • 我正在尝试更新JTable(或data?)的行在我对一行执行删除操作后,当选择另一行时,可以编辑所选行。当前删除该行将使已删除行下方的行上移,但如果选择了该行号并尝试进行编辑,则会返回(JOptionPane),就像未选择任何内容一样。它似乎没有“刷新”数据(?)。 这是一个SCCE,希望有人可以运行它并指出问题。我试着尽可能地缩小它,以便于复制/粘贴: 我在这里看到这个问题的各种形式都有一些不同

  • 本文向大家介绍HTML 插入,删除或粘贴,包括了HTML 插入,删除或粘贴的使用技巧和注意事项,需要的朋友参考一下 示例 要将文本标记为已插入,请使用<ins>标签: 要将文本标记为已删除,请使用<del>标签: 要删除文本,请使用<s>标签:            

  • 问题内容: 我的数据库中有一个计算,需要在更新触发器之后为“ table1”更新“ field1”。 更新该字段的问题将导致更新后触发器触发并执行冗长的过程并显示错误。 请告知在执行“更新后”触发器之后如何使“ field1”更新,而又不使“更新后”触发器再次执行。 我知道我不能将After触发器与NEW配合使用。 谢谢 问题答案: 可以使用基于上下文变量的自定义锁定机制,以防止重复调用AFTER

  • 问题内容: 假设我使用jQuery将新内容加载到特定的DIV元素中。如果现在我想从该DIV元素内部捕获事件,我认为必须以某种方式更新DOM?处理此问题的最佳方法是什么? 编辑:这是我的意思的示例: 同一级别的文件包含 文件“视图”包含 如果您尝试此操作,则将在您第一次按下Edit时看到该按钮变为View,但之后不再更改。为什么是这样? 问题答案: 像这样使用live: