javaswingjtableabstracttablemodel

Adding a Row in a Jtable with AbstractTableModel


I'm trying to add a row into the Jtable that extends AbstractTableModel as the following code shows:

class AbstractTable extends AbstractTableModel
{
    String[] columNames = {"name", "cc", "age", "phone", "date", "amoun"};      
    Object[][] dataRow = {{"harry", "1234","21","23594","13/3/2","3000"} };

    @Override
    public int getColumnCount()
    {
        return columNames.length;
    }

    @Override
    public int getRowCount()
    {
        return dataRow.length;
    }

    public String getColumnName(int col)
    {
        return columNames[col];//cast from object to string.            
    }

    @Override
    public Object getValueAt(int row, int col)
    {
        return dataRow[row][col];
    }

    public void setValueAt(Object value, int row, int col)
    {
        dataRow[row][col] = value;
        fireTableCellUpdated(row, col);
    }
}

Here I implement a button that tries to add a row into the Jtable model once is pressed, but it is not working and throwing an exception:

java.lang.ClassCastException: AbstractTable cannot be cast to javax.swing.table.DefaultTableModel

public void actionPerformed(ActionEvent e)
{           
    if(e.getActionCommand().equals("add client"))
    {
        Object[] dataList = {"", "", "", "", "", ""};               

        AbstractTableModel defaut = (AbstractTableModel) table.getModel();

        ((DefaultTableModel) defaut).addRow(dataList);

        labelStatus.setText("Cliente Agregado.");
    }

How can I add a row in this code properly ?


Solution

  • How can i add a row in this code properly ?

    You need to re-do your model. Currently you're hard-coding the data in fixed-sized arrays which will hamstring your ability to add data. Instead:

    Alternatively: don't have your model extend AbstractTableModel but rather have it extend DefaultTableModel and use its methods. If you go this route, you'd not have your class hold a 2D array but rather would use the Default's own data nucleus, one that you can fill and modify via the Default's super constructors and methods. You'd also do well to create an addRow method overload, one that accepts a parameter of class RowType

    For example assuming a RowData class with fields and setters and getters to match the columns, you could extend DefaultTableModel to look something like this:

    public class MyTableModel extends DefaultTableModel {
        public static final String[] COLUMN_NAMES = { "name", "cc", "age", "phone", "date", "amount" };
    
        public MyTableModel() {
            super(COLUMN_NAMES, 0);
        }
    
        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (getRowCount() > 0 && getValueAt(0, columnIndex) != null) {
                return getValueAt(0, columnIndex).getClass();
            }
            return super.getColumnClass(columnIndex);
        }
    
    
        public void addRow(RowData rowData) {
            if (rowData == null) {
                throw new IllegalArgumentException("rowData cannot be null");
            }
            Vector<Object> rowVector = new Vector<>();
            rowVector.add(rowData.getName());
            rowVector.add(rowData.getCc());
            rowVector.add(rowData.getAge());
            rowVector.add(rowData.getPhone());
            rowVector.add(rowData.getDate());
            rowVector.add(rowData.getAmount());
            rowVector.add(rowData.getCc());
    
            super.addRow(rowVector);
        }
    
        // TODO: methods to return a row as a RowData object
    }
    

    Then you could use either the super's addRow(Vector data) method or your overload above.