javaswingjtabledefaulttablemodel

Rows inserted into a DefaultTableModel don't show


In my Java 8 app I use a SwingWorker to get some data from a database and call publish once I know the data for a full row that I then want to add to my table:

DefaultTableModel dtm123 = (DefaultTableModel) myTable.getModel();

@Override
protected void process(List<Integer> chunks) {
    if(chunks!=null) {
        ListIterator<Integer> li = chunks.listIterator();

        while(li.hasNext()) {
            dtm123.addRow(myDataList.get(li.next()).getRowArray());
        }                    
    }
}

dtm123.getRowCount() is increased every time (I checked) but the table isn't updated to actually show the new rows. I tried to update it manually, which didn't work either:

dtm123.fireTableRowsInserted(0, dtm123.getColumnCount()-1);

Here's the weird thing: If I use the full version, it's filling the table just fine:

((DefaultTableModel) myTable.getModel()).addRow(myDataList.get(li.next()).getRowArray());

Can you not use the shorter version for filling a table? dtm123 isn't used anywhere else, so what's the difference between the two versions?

Edit:

Filling it directly like this (without the SwingWorker) works:

myTable.setModel(new DefaultTableModel(
    new Object[][] {},
    new Object[] {"blaA","blaB","blaC"}
));

DefaultTableModel dtm123 = (DefaultTableModel) myTable.getModel();
dtm123.addRow(new String[] {"bla1A","bla1B","bla1C"});
dtm123.addRow(new String[] {"bla2A","bla2B","bla2C"});
dtm123.addRow(new String[] {"bla3A","bla3B","bla3C"});
dtm123.addRow(new String[] {"bla4A","bla4B","bla4C"});
dtm123.addRow(new String[] {"bla5A","bla5B","bla5C"});
dtm123.addRow(new String[] {"bla6A","bla6B","bla6C"});
dtm123.addRow(new String[] {"bla7A","bla7B","bla7C"});

Looks like the SwingWoker is the problem but why? process is running on the main thread, which has to be used for UI updates, and there are no exceptions or error messages.


Solution

  • Fixed it - there were two reasons why it didn't work:

    1. Setting the model of a table (myTable.setModel(new DefaultTableModel(...add info here...));) and creating the columns has to be done on the main/UI thread too.

    2. process is called at a seemingly random point in time after calling publish() and there's no way to tell beforehand how many chunks there will be (could be just one or all of them), so you have to make sure that you get the DefaultTableModel after you set up the columns. To guarantee this, either set up the columns before you call publish() the first time (but still outside doInBackground - see 1.) or call publish for a "zeroth" time to set them up (see code below). In hindsight this seems pretty obvious...

    If you're using a SwingWorker like me, you can do something along the lines of:

    DefaultTableModel dtm123;
    
    @Override
    protected void process(List<Integer> chunks) {
        if(chunks!=null) {
            ListIterator<Integer> li = chunks.listIterator();
            int next;
    
            while(li.hasNext()) {
                next = li.next();
    
                if(next==-1) {
                    //Set up columns/column titles here
                    myTable.setModel(new DefaultTableModel(
                        new Object[][] {},
                        columnHeaderArray
                    ));
                    dtm123 = (DefaultTableModel) myTable.getModel();
                } else {
                    //Add new rows here
                    dtm123.addRow(myDataList.get(next).getRowArray());
                }
            }
        }
    }
    

    Use publish as usual but once you know the columns' titles, call publish(-1) to set them up (of course, before you add the rows).