【发布时间】:2011-06-13 12:31:40
【问题描述】:
我已经通过具有 (Object[][] data, String[] headers) 构造函数的 DefaultTableModel 填充了 JTable。用户可以编辑表格,我希望能够将新数据加载回数组 (Object[][])。请注意,我宁愿不只是一点一点地更新数组,而是能够完全从表中加载一个新数组。如何做到这一点?
【问题讨论】:
我已经通过具有 (Object[][] data, String[] headers) 构造函数的 DefaultTableModel 填充了 JTable。用户可以编辑表格,我希望能够将新数据加载回数组 (Object[][])。请注意,我宁愿不只是一点一点地更新数组,而是能够完全从表中加载一个新数组。如何做到这一点?
【问题讨论】:
我想对 Manidip Sengupta 的回答提出一些小改进。与其将 table.getModel() 转换为适当的类,不如简单地使用 TableModel。这也使代码更具可重用性(实际上使用哪个 TableModel 实现并不重要)。
public Object[][] getTableData (JTable table) {
TableModel dtm = table.getModel();
int nRow = dtm.getRowCount(), nCol = dtm.getColumnCount();
Object[][] tableData = new Object[nRow][nCol];
for (int i = 0 ; i < nRow ; i++)
for (int j = 0 ; j < nCol ; j++)
tableData[i][j] = dtm.getValueAt(i,j);
return tableData;
}
【讨论】:
我收回这一点,第二个想法是,您不需要任何类型转换 - TableModel 是一个接口,它具有您需要的所有 3 个方法调用。 :)
总结:获取表的模型,检查其类并将其类型转换为适当的类(Abstract 或 Default TableModel),并使用其方法加载新创建的数组。一些伪代码:
public Object[][] getTableData (JTable table) {
DefaultTableModel dtm = (DefaultTableModel) table.getModel();
int nRow = dtm.getRowCount(), nCol = dtm.getColumnCount();
Object[][] tableData = new Object[nRow][nCol];
for (int i = 0 ; i < nRow ; i++)
for (int j = 0 ; j < nCol ; j++)
tableData[i][j] = dtm.getValueAt(i,j);
return tableData;
}
您的标题不应被用户编辑更改。希望有帮助。问候, - M.S.
【讨论】:
我已经通过 DefaultTableModel 用(Object[][] data, String[] headers)填充了一个 JTable
DefaultTableModel 是一个动态模型,这意味着可以动态添加行和列。数组不是动态的,因此当您使用数组创建 DefaultTableModel 时,数组中的数据会被复制到 Vector 的 Vector。
我希望能够将新数据加载回数组 (Object[][])。 我宁愿不只是一点一点地更新数组
很遗憾,您将不得不逐个单元格地更新数组,因为数据未存储在二维数组中。
或者,由于 DefaultTableModel 确实使用向量的向量来存储数据,因此您可以使用 getDataVector() 方法来访问数据。然后从 Vector 中获取每一行并在行 Vector 上调用 List.toArray() 方法,然后再将其添加到数组中。
无论哪种方式,您都需要遍历模型中的向量。
如果您想使用 2D 数组作为 TableModel 的存储,那么您将需要创建一个自定义 TableModel 使用提供的数组来存储数据。实现 TableModel 接口的所有必需方法后,您需要提供一个 getTableDataArray() 方法来返回对数组的引用。
【讨论】:
使用开箱即用的 JTable 实现,您不能。当您使用 Object[][] rowData 初始化 JTable 时,该 rowData 由匿名 AbstractTableModel 实例使用,但不能从外部访问。
public JTable(final Object[][] rowData, final Object[] columnNames) {
this(new AbstractTableModel() {
public String getColumnName(int column) { return columnNames[column].toString(); }
public int getRowCount() { return rowData.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) { return rowData[row][col]; }
public boolean isCellEditable(int row, int column) { return true; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
fireTableCellUpdated(row, col);
}
});
}
您可以考虑对 JTable 和 AbstractTableModel 进行子类化,并在 JTable 中“覆盖”此构造函数以创建您自己的 TableModel 实现,该实现将持有该 Object[][] 引用并以Object[][] getRowData() 返回它。或者,在构造函数中调用 super(...) 之后,将 rowData 保留为 JTable 子类本身中的一个字段——如果您真的不关心 MVC。
但是您需要确保在编辑表格后,初始模型被保留,而不是被带有setModel 的新模型对象(当然,不同类型的)替换。如果是这种情况,您想要实现的目标是不可能实现的——您需要遍历所有单元格。
【讨论】:
不适用于现有的默认表模型。根据经验,您应该使用默认表模型。您应该实现自己的table model (MyTableModel)。您可以实现TableModel 或扩展AbstractTableModel。我建议后者,因为它提供了一些不错的实用方法。有两种方法可以实现您正在做的事情
MyTableModel 的新实例中并调用JTable.setModel()。 MyTableModel 调用中创建一个方法,例如replaceData(T[][] data)。保留对表格当前显示的模型的引用。每当您想替换数据时,请致电replaceData()。假设您正在扩展AbstractTableModel,然后调用fireTableChanged() 通知表。【讨论】: