Threads and jtable

会有一股神秘感。 提交于 2019-12-02 08:27:33

The first rule of Swing - Don't modify the UI from any Thread other then the Event Dispatching Thread

First, make sure your updates calls are synchronized, using SwingUtilities#invokeLater or if the update is critical to the code path SwingUtilities#invokeAndWait

When adding rows to the table model, you are responsible for firing the update events required to notify the view that the model has changed.

If you're using a DefaultTableModel then this will be done for you, if you're using an AbstractTableModel or you own TableModel then you will need to do this yourself.

The easiest way is to write an implementation that extends from AbstractTableModel and call AbstractTableModel#fireTableRowsInserted(int, int) from within your add method, this will tell the JTable that the model has added rows and will cause the table to update itself accordiningly.

Don't be fooled, using fireTableRowsInserted is generally faster then using fireTableDataChanged when adding rows to a table model as the whole table doesn't need to be repainted. If you've significantly changed the table (added/removed/updated lots of rows), then fireTableDataChanged would be quicker than a series individual insert/deleted/updated calls.

Have a look at How to Use Tables and Concurrency in Swing for more information

UPDATED

As it appears as I may not have made myself clear. The model is responsible for fire the events. That means, that within your add method, you should be calling fireTableRowsInserted. You should refrain from calling these methods from an external source.

Swing is not thread-safe. If you need to modify Swing components from Threads other than the AWT event dispatch thread, use

SwingUtilities.invokeLater(new Runnable(){public void run() {
 // your code
}});
public class TM extends AbstractTableModel {
final List<Integer>ids;

public TM() {
    ids = new ArrayList();
}

@Override
public int getRowCount() {
    return ids.size();
}

@Override
public int getColumnCount() {
    return 1;
}

@Override
public String getColumnName(int column) {
    if(column == 0) {
        return "ID";
    } else {
        return "UNDEF";
    }
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    if(columnIndex == 0) {
        return ids.get(rowIndex);
    } else {
        return "NaN";
    }
}

public void addId(final int id) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            insertNewRow(id);
        }
    });
}

private void insertNewRow(int id) {
    ids.add(id);
    int rowIndex = ids.size();
    fireTableRowsInserted(rowIndex, rowIndex);
}

}

//Somewhere in your code
TM myModel = new TM();
myTable = new JTable(myModel);


//Somewhere from thread:
myModel.addId(123);

//Somewhere from another thread:
myModel.addInd(455);

Could you please clarify how you adding rows? Hopefully using model, right? Once new row added you have to call model's method fireTableDataChanged/not the best option/ or fireTableRowsInserted/better/ And dont forget to do it using SwingUtilities.invokeLater to avoid problems Swing

Also when trying to update a model of JTable, its important to remove any tableModelListener before updating the model. I saw this observation with model.addColumn() and table.moveColumn(). Make sure you add the tableModelListener after whatever changes gets made to the model.

I hope you know that Swing is not thread safe(with few exceptions) . You need to take care of that in your code.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!