Java 中 JTable 的 JDBC TableModel?
我想将数据库表显示为 JTable。我以前从未使用过 JTable,所以我用 google 搜索了 JTable 和 TableModel。
通过谷歌搜索,我可以编写自己的自定义 TableModel,它显示存储在
Object[][] data;
现在的数据,我想将我的数据库表数据显示到 JTable 中。我也进行了搜索,并对此有了一定的了解,但仍然对 AbstractTableModel 的实现类中的内容应该放在哪里感到困惑。
以下是自定义TableModel的代码。
public abstract class AbstractPOLDATTableModel extends AbstractTableModel {
protected boolean DEBUG = false;
private String[] columnNames;
private Object[][] data;
protected AbstractPOLDATTableModel(String[] columnNames, Object[][] data) {
this.columnNames = columnNames;
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
@Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
@Override
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
@Override
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
现在,如何更改上述代码,使我的 JTable 具有以下功能:
- 它显示数据库中的数据
- 用户可以直接编辑表,当他单击“保存”按钮时,更改会反映在数据库数据中
- 用户可以直接插入数据。
- 用户可以直接删除数据。
I want to display a database table as a JTable. I have never used JTable before so I googled JTable and TableModel.
With that googling, I am able to write my own custom TableModel which show data stored in
Object[][] data;
Now, I want to show my database table data into JTable. I searched that also and have got an idea of that but still confused about what should goes where in the implementation class of AbstractTableModel.
Following is the code of custom TableModel.
public abstract class AbstractPOLDATTableModel extends AbstractTableModel {
protected boolean DEBUG = false;
private String[] columnNames;
private Object[][] data;
protected AbstractPOLDATTableModel(String[] columnNames, Object[][] data) {
this.columnNames = columnNames;
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
@Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
@Override
public boolean isCellEditable(int row, int col) {
if (col < 2) {
return false;
} else {
return true;
}
}
@Override
public void setValueAt(Object value, int row, int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data[row][col] = value;
fireTableCellUpdated(row, col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
Now, how to change the above code so that my JTable can have the follwing features:
- It shows data from the database
- User can edit the table directly and when he clicks on a "save" button, the changes reflect in the database data
- User can insert data directly.
- User can delete data directly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我假设您已经根据 Adamski 在上一个问题中的建议实现了 1。另外,根据 Sanoj 的建议,更改为使用某种列表来存储数据。
要支持 2-4,您必须确保从数据库中提取的数据仅来自一个表,并且不涉及派生数据(例如聚合、column1 + column2)。如果您打算让用户过滤行,您将需要跟踪您的
where
子句。在每一行中,存储另一行(我们称之为updatedRow),该行表示用户使用GUI 所做的更新。对行进行任何更新后,需要用包含更新数据的新行填充此字段。单击“保存”时,您将对具有非空updatedRow的所有行运行更新查询,使用updatedRow中的数据更新数据库,这些数据与原始行中的数据不匹配(如果用户将数据更改回原来的方式,则不会更新)原来是这样)。您可能还有另一个“撤消更新”按钮,该按钮使用具有非空 updateRow 的所有行的原始数据填充表。
我强烈建议您在构成主键的字段上存储额外的元数据,并防止这些字段被更改,因为对此类列的更新可能会很昂贵(因为它们可能已建立索引,并且可能附加了一些 RI 约束)。这应该通过使此类列不可编辑来反映在 GUI 中。更新中的
where
子句将仅使用这些字段而不是所有字段(您仍然需要用户在 1 中设置的其他过滤器)。我建议分两步进行。用户首先单击一个按钮,向表中添加一行。输入数据后,用户单击另一个按钮插入数据库(或者您可以将此功能与“保存”按钮中的更新结合起来)。如果主键列不是某些自动生成的 ID,您将需要允许新插入的行的主键字段可编辑。
为了区分哪些行已经在数据库中,哪些行不在数据库中,我建议存储新插入的行的列表。
如果您让用户仅选择要在表中显示的某些列,您将需要确定如何处理未显示的列(例如,让数据库设置默认值,使用自动生成的 ID 填充)。
最好的实现方式可能是在每行上都有一个复选框,然后当单击“删除”按钮时,它会调用 SQL 使用 1 中的过滤器和 2 中提到的主键元数据删除每个选中的行,以及将其从表中删除。
一般注意事项:
相同的 setValueAt 方法将用于更新和插入的行,但您需要不同的行为。您希望为更新设置 UpdatedRow,但在编辑要插入的行时则不然。
您将如何处理诸如未满足约束或无效输入(例如数字字段中的“abcde”)之类的错误?
您将如何处理诸如未满足约束或无效输入(例如,数字字段中的“abcde”)
SQL 注入。
I'm assuming you've implemented 1 according to what Adamski suggested in your previous question. Also, as suggested by Sanoj, change to using some sort of List to store your data.
To support 2-4, you must ensure that the data you're pulling out of the database comes from only one table and involves no derived data (eg. aggregations, column1 + column2). You will need to keep track of your
where
clause, if you intend to let the user filter rows.Within each Row, store another Row (let's call it updatedRow) that represents the updates the user has made using the GUI. Once any update is made to the row, this field needs to be populated with a new Row containing the updated data . When "Save" is clicked, you run update queries for all Rows with a non-null updatedRow, updating the database with data in updatedRow which do not match those from the original Row (don't update if the user changes data back to how it was originally). You might also have another "Undo Updates" button which populates the table with the original data for all Rows with a non-null updatedRow.
I would strongly recommend that you store additional metadata on which fields form the primary key and prevent those from being changed, as updates to such columns may be expensive (since they are presumably indexed and may have some RI constraints attached). This should be reflected in the GUI by making such columns not editable. The
where
clause in updates would use only these fields rather than all fields (you will still need other filters that your user set in 1).I'd suggest a two step process. The user starts by clicking a button which adds a row to the table. After entering data, the user clicks another button to insert into the database (or you can combine this functionality with updates in the "save" button). You will need to allow primary key fields to be editable for newly inserted rows if the primary key columns aren't some auto-generated ID.
To different between which Rows are already in the database and which ones aren't, I'd suggest storing a list of newly inserted Rows.
If you let the user pick only certain columns to display in the table, you will need to determine how to deal with the columns that aren't being displayed (eg. let the database set a default, populate with auto-generated ID).
Probably best to implement this by having a checkbox with each Row, then when the "Delete" button is clicked, it calls SQL to delete each checked Row using the filter from 1 and primary key metadata mentioned in 2, as well as to remove it from the table.
General considerations:
The same setValueAt method will be used for both updated and inserted Rows, but you want different behaviour. You want to set updatedRow for updates, but not when editting Rows you're about to insert.
How will you handle errors such as constraints not being met or invalid input (eg. 'abcde' in a numeric field)?
SQL injection.