简体   繁体   中英

How to Retrieve JTable Data as an Array

I've populated a JTable through a DefaultTableModel with the ( Object[][] data, String[] headers) constructor. Users can edit the table, and I want to be able to load the new data back into an array ( Object[][] ). Note that I'd rather not just update the array bit by bit, but be able to just completely load a new array from the table. How can this be done?

I take that back, on 2nd thoughts, you dont need any typecasting - TableModel is an interface that has all the 3 method calls you need. :)

Summary: Get the model for the table, check its class and typecast it to appropriate class (Abstract or Default TableModel), and use its methods to load a newly created array. Some psuedoCode:

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;
}

Your headers should not have changed by user-edits. Hope that helps. Regards, - MS

I'd like to suggest a small improvement on Manidip Sengupta's answer. Rather than casting table.getModel() to the appropriate class, it is better to simply work with TableModel. This makes the code more re-usable too (it doesn't matter which implementation of TableModel is actually being worked with).

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;
}

I've populated a JTable through a DefaultTableModel with the (Object[][] data, String[] headers)

The DefaultTableModel is a dynamic model, which means rows and columns can be added dynamically. Arrays are not dynamic so when you create a DefaultTableModel using arrays, the data from the arrays is copied to a Vector of Vectors.

I want to be able to load the new data back into an array (Object[][]). I'd rather not just update the array bit by bit

Unfortunately you will have to update the array cell by cell since the data is not stored in a 2D array.

Or, since the DefaultTableModel does use a Vector of Vectors to store the data you can use the getDataVector() method to access the data. Then you get each row from the Vector and invoke the List.toArray() method on the row Vector before adding it to your array.

Either way you will need to loop through the Vectors in the model.

If you want to use the 2D array as storage for the TableModel, then you will need to create a custom TableModel that uses the supplied array for the data storage. After implemting all the required methods of the TableModel interface you will need to provide a getTableDataArray() method to return the reference to the array.

Not with the existing default table model. As a rule of thumb, you should ever use the default table model. You should implement your own table model ( MyTableModel ). You can either implement TableModel or extend AbstractTableModel . I suggest the latter as it provides some nice utility methods. There are 2 ways to achieve what you are doing

  1. populate your new data into a new instance of MyTableModel and call JTable.setModel() .
  2. A second way is to create a method in MyTableModel call eg, replaceData(T[][] data) . Hold a reference to the model that the table is current displaying. Whenever you want to replace the data, call replaceData() . Assuming you are extending AbstractTableModel , then call fireTableChanged() to notify the table.

With the out-of-the-box JTable implementation, you can't. When you initialize a JTable with Object[][] rowData that rowData is used by an anonymous AbstractTableModel instance but it's not accesible as such from outside.

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);
        }
    });
}

You could consider to subclass both JTable and AbstractTableModel and "overwrite" this constructor in JTable to create your own TableModel implementation that will hold that Object[][] reference and return it with Object[][] getRowData() . Or just keep the rowData as a field in the JTable subclass itself after calling super(...) in that constructor -- if you don't really care about MVC.

But you need to make sure that after the table is edited, the initial model is preserved and not replaced by a new model object (of course, of a different type) with setModel . If this is the case, what you want is impossible to achieve -- you will need to iterate through all the cells.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM