0

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) {
    }
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
mav
  • 121
  • 3
  • 10
  • You have a problem (table remains empty), please provide us snippets of your code in order to allow us to help you – Maxim Shoustin Nov 15 '12 at 22:38
  • 1
    @mav for better help sooner post an [SSCCE](http://sscce.org/), with hardcoded values for Threads, short, runable, compilable, otherwise everything here could be only shots to the dark – mKorbel Nov 16 '12 at 07:16

6 Answers6

8

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.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I would say that the table model is responsible for firing the update events. The only reason `AbstractTableModel` has public fire methods is for delegation. – Steve Kuo Nov 15 '12 at 23:26
  • @SteveKuo Precisely, the "model" is responsible for dispatching the events. When the OP calls there add method, they should be calling the appropriate `fireTableXxx` from with in that method. Sorry if I didn't make that clear – MadProgrammer Nov 15 '12 at 23:31
  • @Steve Kuo same issues with DefaultTableModel, in the case that you'll modified model value out of EDT – mKorbel Nov 16 '12 at 07:14
  • If you look at `DefaultTableModel` source code, it internally fires the change event when addRow, insertRow, etc are called. My point is that a well written table model should automatically fire the change events when its state has changed. The client modifying the table model should not need to manually fire the change events. – Steve Kuo Nov 16 '12 at 19:39
  • @SteveKuo and we agree with you. The other issue to consider is that Swing is thread unsafe, so even if your model is doing what it should do, if the caller fails to honour the EDT contract, you're still going to have issues ;) – MadProgrammer Nov 16 '12 at 19:57
1

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
}});
Maxim Shoustin
  • 77,483
  • 27
  • 203
  • 225
1
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);
rimas
  • 757
  • 2
  • 8
  • 18
  • `and each of them have to add a row to the jTable`, please where is methods for `addRow`, there are only `getXxx` methods, please to delete this answer – mKorbel Nov 16 '12 at 15:45
  • Please, scroll down code a little and find addRow(int id) method. In small example I posted my table have only one column and I using very simple storage(List). Calling addRow method you able to insert new row in model and update table in thread-safe manner. – rimas Nov 16 '12 at 16:21
0

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

rimas
  • 757
  • 2
  • 8
  • 18
  • yes with table.setModel(new DefaultTableModel(data, columnName)); – mav Nov 16 '12 at 12:59
  • More correct will be create own table model which extends DefaultTableModel and then set it to your table. See example below – rimas Nov 16 '12 at 15:17
0

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.

suppie
  • 1,087
  • 8
  • 10
-1

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

Addict
  • 803
  • 2
  • 9
  • 16