【发布时间】:2011-01-12 15:51:44
【问题描述】:
我想显示一个 JTable,它按原样显示来自数据库表的数据。
到目前为止,我一直使用 JTable 来显示来自 Object [ ][ ] 的数据。
我知道显示数据的一种方法是首先将数据库表转换为 Object [ ][ ],但是还有其他更简单但更强大和灵活的方法吗?
【问题讨论】:
我想显示一个 JTable,它按原样显示来自数据库表的数据。
到目前为止,我一直使用 JTable 来显示来自 Object [ ][ ] 的数据。
我知道显示数据的一种方法是首先将数据库表转换为 Object [ ][ ],但是还有其他更简单但更强大和灵活的方法吗?
【问题讨论】:
我知道这个问题已经过时了,但是对于任何遵循 Adamski 解决方案的人来说,在 gui 和 SwingWorker 线程之间共享 ResultSet 和 ResultSetMetadata 时应该小心。在将这种方法与 SQLite 一起使用时,我得到了一个不一致的内部状态异常。解决方案是在执行 SwingWorker 之前将任何元数据加载到私有字段,并让 getter 函数(getColumnName 等)改为返回字段。
【讨论】:
用 ResultSet 填充 jTable 的最佳方法
1) 结果集“rs”中填充了您需要的数据。 2) JTable "jTable1" 是事先创建好的 3) 表头是事先实现的
java.sql.ResultSet rs = datacn.executeSelectQuery(query);
//Filling JTable with Result set
// Removing Previous Data
while (jTable1.getRowCount() > 0) {
((DefaultTableModel) jTable1.getModel()).removeRow(0);
}
//Creating Object []rowData for jTable's Table Model
int columns = rs.getMetaData().getColumnCount();
while (rs.next())
{
Object[] row = new Object[columns];
for (int i = 1; i <= columns; i++)
{
row[i - 1] = rs.getObject(i); // 1
}
((DefaultTableModel) jTable1.getModel()).insertRow(rs.getRow() - 1,row);
}
【讨论】:
在 JTable 中显示数据库数据的另一种强大而灵活的方法是将查询的结果数据加载到 CachedRowSet,然后使用 TableModel 适配器将其连接到 JTable。
George Reese 的这个book 为他的班级RowSetModel 提供the source code,以将RowSet 改编为TableModel。开箱即用地为我工作。我唯一的改变是为这个类取了一个更好的名字:RowSetTableModel。
RowSet 是 ResultSet 的子接口,在 Java 1.4 中添加。所以一个 RowSet 是一个 ResultSet。
CachedRowSet 实现为您完成工作,而不是像本页其他答案中讨论的那样创建 Row 类、Row 对象列表和 ResultSetMetaData。
Sun/Oracle 提供了一个reference implementation 的 CachedRowSet。其他供应商或 JDBC 驱动程序也可能提供实现。
【讨论】:
我给出了一个在 JTable 中显示数据库表数据的小方法。您只需将数据库表的结果集作为参数传递。
// rs is the ResultSet of the Database table
public void displayData(ResultSet rs)
{
//jt Represents JTable
//jf represents JFrame
int i;
int count;
String a[];
String header[] = {"1","2","3","4","5"}; //Table Header Values, change, as your wish
count = header.length;
//First set the Table header
for(i = 0; i < count; i++)
{
model.addColumn(header[i]);
}
jt.setModel(model); //Represents table Model
jf.add(jt.getTableHeader(),BorderLayout.NORTH);
a = new String[count];
// Adding Database table Data in the JTable
try
{
while (rs.next())
{
for(i = 0; i < count; i++)
{
a[i] = rs.getString(i+1);
}
model.addRow(a); //Adding the row in table model
jt.setModel(model); // set the model in jtable
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, "Exception : "+e, "Error", JOptionPane.ERROR_MESSAGE);
}
}
【讨论】:
您必须创建一个自定义TableModel,您可以在其中指定数据的来源和方式。
您确实必须首先完全了解JTable + TableModel 的工作原理,然后按照之前发布的答案之一进行操作。
【讨论】:
根据您已经完成的工作以及您愿意做什么,我一直在使用 Netbeans 及其 Beans Binding 支持来非常成功地开发数据库驱动的应用程序。您将 JTable 绑定到数据库,它会自动构建 JPA 查询。
【讨论】:
我建议采用以下方法:
Row 类来表示从ResultSet 读取的行。这可以是 Object[] 的简单包装器。List<Row> 集合,并将AbstractTableModel 子类化以由该集合支持。SwingWorker 来填充您的List<Row>,方法是从后台线程(即在doInBackground() 方法中)上的底层ResultSet 读取。调用SwingWorker 的publish 方法将Rows 发布回事件调度线程(例如每100 行)。SwingWorker 的process 方法并读取最新的行块时,将它们添加到您的List<Row> 并触发适当的TableEvents 以更新显示。ResultSetMetaData 确定TableModel 定义中每一列的Class。这将导致它们被正确渲染(如果您仅使用 2D Object[][] 数组,则不会出现这种情况)。这种方法的优点是在处理较大的ResultSets 时 UI 不会锁定,并且显示会随着结果的处理而增量更新。
编辑
在下面添加了示例代码:
/**
* Simple wrapper around Object[] representing a row from the ResultSet.
*/
private class Row {
private final Object[] values;
public Row(Object[] values) {
this.values = values;
}
public int getSize() {
return values.length;
}
public Object getValue(int i) {
return values[i];
}
}
// TableModel implementation that will be populated by SwingWorker.
public class ResultSetTableModel extends AbstractTableModel {
private final ResultSetMetaData rsmd;
private final List<Row> rows;
public ResultSetTableModel(ResultSetMetaData rsmd) {
this.rsmd = rsmd;
this.rows = new ArrayList<Row>();
}
public int getRowCount() {
return rows.size();
}
public int getColumnCount() {
return rsmd.getColumnCount();
}
public Object getValue(int row, int column) {
return rows.get(row).getValue(column);
}
public String getColumnName(int col) {
return rsmd.getColumnName(col - 1); // ResultSetMetaData columns indexed from 1, not 0.
}
public Class<?> getColumnClass(int col) {
// TODO: Convert SQL type (int) returned by ResultSetMetaData.getType(col) to Java Class.
}
}
// SwingWorker implementation
new SwingWorker<Void, Row>() {
public Void doInBackground() {
// TODO: Process ResultSet and create Rows. Call publish() for every N rows created.
}
protected void process(Row... chunks) {
// TODO: Add to ResultSetTableModel List and fire TableEvent.
}
}.execute();
【讨论】: