Volodymyr Levytskyi
Volodymyr Levytskyi

Reputation: 3432

Why doesn't JTable update its view when adding new rows to DefaultTableModel?

I have weird problems with JTable. Method addRows doesn't force jTable to update its view:

public class VirusTable extends JTable {

    private String[] columnNames = { "", "Virus", "Path", "Size", "Created", "Last Mofified" };

    DefaultTableModel tableModel;

    public VirusTable() {
        super();

        tableModel = (DefaultTableModel) super.getModel();
        tableModel.setColumnIdentifiers(columnNames);

        // super.setFillsViewportHeight(true);
        // super.setIntercellSpacing(new Dimension(5, 5));
        // super.setRowSelectionAllowed(false);
        // super.setColumnSelectionAllowed(false);
    }

    public void addRows(Collection<UserFile> viruses) {
        System.out.println("AddRows=" + viruses);

        for (UserFile virus : viruses) {
            tableModel.addRow(virus.toRowData());
        }
//      tableModel.fireTableDataChanged();
        // tableModel.fireTableStructureChanged();
        int rowCount = super.getRowCount();
//      super.revalidate();
//      super.repaint();
        System.out.println("rowCount=" + rowCount);
    }
}

addRows method is called from SwingWorker.process method. Interestingly that rowCount is always correct but rows are not displayed on JTable.

I tried everything and nothing helps. I wanted to create short runnable demo but I cannot implement this bug.

I posted this project on github and described what is wrong there.

Upvotes: 0

Views: 96

Answers (2)

sgbj
sgbj

Reputation: 2274

camickr is correct, there are actually two instances of your VirusTable (and in fact MainFrame as well, but only one of them is visible) being created. You've provided a way to access the MainFrame object by basically turning it into a singleton, but without the constraint that only one instance can ever be created. IMHO, you could've done this a lot better without creating a static getInstance method in your MainFrame class.

Anyhoo, in your main method, you do this:

public static void main(String[] args) throws IOException {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            new MainFrame().setVisible(true);
        }
    });
}

But because of the way you've coded your application, you should be doing this (not that I recommend this approach):

public static void main(String[] args) throws IOException {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            MainFrame.getInstance().setVisible(true);
        }
    });
}

Thank camickr, not me.

Upvotes: 1

Kevin Day
Kevin Day

Reputation: 16363

Maybe you are making changes to a Swing model from a thread other than the event dispatch thread (hard to tell from your code)? All Swing interactions must be done from the EDT, so either wrap your table update in SwingUtilities.invokeLater() (if you want it to update as each entry is found) or add the items to the table model in the done() method of SwingWorker which forces the execution on the EDT.

Upvotes: 0

Related Questions