javaeclipseswingabstracttablemodel

How to refresh table model after data and size change


My project is simple implementation of app like MC, NC or Total Commander. I use 2 JTables with custom model that extends AbstractTableModel and my problem is updating these tables with new data and size.

Whenever I try to update it with my method, I run into ArrayIndexOutOfBoundsException, altough I make sure to recreate my data array with new size, based off given arguments. Also, if I wait long enough, my table will indeed refresh properly but it's stuttering a lot, it's view is going crazy and it's overall unusable although it works in some weird, twisted way.

Here's my method that is supposed to refresh my Table's model:

public class TableModel extends AbstractTableModel { 

private SimpleDateFormat df2 = new SimpleDateFormat("dd/MM/yyyy HH:mm");
private String[] fieldNames = {"Name", "Extension", "Size", "Time"};
private Object[][] data;

public void UpdateTable(String path)
{
    File[] list = (new File(path).listFiles());

    data = new Object[list.length][fieldNames.length];

    for(int i=0; i<list.length;i++)
    {   
        data[i][0] = list[i].getName();
        if (FilenameUtils.getExtension(list[i].getPath()) == "")
        {
            data[i][1] = "<dir>";
        }
        else{
            data[i][1] = FilenameUtils.getExtension(list[i].getPath());
        }
        data[i][2] = list[i].length();
        data[i][3] = df2.format(new Date(list[i].lastModified()));
    }
}
[...]

And then part of MainFrame class, that is calling that method from within an actionListener.

TableModel model1 = new TableModel(listRoots()[0]);
JTable table = new JTable(model1);
table.setShowGrid(false);
table.setIntercellSpacing(new Dimension(0, 0));
table.setFillsViewportHeight(true);
table.getTableHeader().setReorderingAllowed(false);
JScrollPane scrollPane = new JScrollPane(table);
pane.add(scrollPane, c);

//combo box's actionListener. Is supposed to work like it does in totalCommander
combo.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        model1.UpdateTable(cb.getSelectedItem().toString());
        model1.fireTableDataChanged();
        table.repaint();
    }   
});

I've already tried using "fireTableDataChanged()" in my update method or in SetValueAt(), but it didin't really help or change a thing.


Solution

  • model1.fireTableDataChanged();
    

    Your application code should never invoke that method. It is the job of the custom TableModel to invoke the method

    with custom model that extends AbstractTableModel

    Then you have implemented a method incorrectly.

    Why are you creating a custom model? There is nothing special about your model. You can just use the DefaultTableModel since is supports dynamic changes to the data.

    Your updateTable(...) method could look something like:

    setRowCount(0);
    
    for (...)
    {
        Vector row = new Vector();
        row.addElement(...);
        row.addElement(...);
        addRow( row );
    }
    

    So you first clear the data from the model and then you add the data back in one at a time. As each row is added the appropriate fireXXX method is automatically invoked.

    You can extend the DefaultTableModel to add this method, or just have this as a method in your class.

    Also, method names should NOT start with an upper case character. "UpdateTable(...)" should be "updateTable(...)"`