mav
mav

Reputation: 121

Threads and jtable

I have a problem with jtable.

I have a number of threads and each of them have to add a row to the jTable, but the table remains empty. I'm working with netbeans, the graphics are totally separate from the logic. Can someone help me, please?


this is the code that i use for adding a row

MainGui.java

public void addToTable(String from, String to, int request, int response, String timeElapsed) {
    Object [][] temp = new Object [data.length + 1][5];

    for (int i = 0; i < data.length; i++) {
        for (int j = 0; j < 5; j++) {
            temp[i][j] = data[i][j];
        }
    }

    temp[data.length][0] = from;
    temp[data.length][1] = to;
    temp[data.length][2] = request;
    temp[data.length][3] = response;
    temp[data.length][4] = timeElapsed;

    data = temp;
    table.setModel(new DefaultTableModel(data, columnName));
}

MyThread.java

public void run() {
    try {
        MainGui mg = new MainGui();
        mg.addtotable("null", "null", 0, 0, "null");
    } catch (Exception e) {
    }

Upvotes: 0

Views: 5749

Answers (6)

MadProgrammer
MadProgrammer

Reputation: 347214

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.

Upvotes: 8

suppie
suppie

Reputation: 1097

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.

Upvotes: 0

rimas
rimas

Reputation: 757

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);

Upvotes: 1

rimas
rimas

Reputation: 757

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

Upvotes: 0

Maxim Shoustin
Maxim Shoustin

Reputation: 77904

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
}});

Upvotes: 1

Addict
Addict

Reputation: 823

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

Upvotes: -1

Related Questions