0

我有 jtable 的问题。

我有许多线程,每个线程都必须向 jTable 添加一行,但表仍然是空的。我正在使用 netbeans,图形与逻辑完全分开。有人能帮助我吗?


这是我用来添加一行的代码

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) {
    }
4

6 回答 6

8

Swing 的第一条规则 -不要从除事件调度线程之外的任何线程修改 UI

首先,确保您的更新调用是同步的,使用SwingUtilities#invokeLater或者如果更新对代码路径至关重要SwingUtilities#invokeAndWait

向表模型添加行时,您负责触发通知视图模型已更改所需的更新事件。

如果您使用的是 aDefaultTableModel那么这将为您完成,如果您使用的是 anAbstractTableModel或您拥有TableModel,那么您将需要自己执行此操作。

最简单的方法是编写一个从 add 方法扩展AbstractTableModel和调用的实现AbstractTableModel#fireTableRowsInserted(int, int),这将告诉JTable模型已添加行并将导致表相应地更新自身。

不要被愚弄,在向表模型添加行时,使用fireTableRowsInserted通常比使用更快fireTableDataChanged,因为不需要重新绘制整个表。如果您对表进行了重大更改(添加/删除/更新了很多行),那么fireTableDataChanged将比一系列单独的插入/删除/更新调用更快。

查看如何在 Swing 中使用表并发以获取更多信息

更新

看起来我可能没有说清楚。模型负责触发事件。这意味着,在您的 add 方法中,您应该调用fireTableRowsInserted. 您应该避免从外部源调用这些方法。

于 2012-11-15T22:40:46.543 回答
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);
于 2012-11-16T15:26:25.627 回答
1

Swing 不是线程安全的。如果需要从 AWT 事件调度线程以外的线程修改 Swing 组件,请使用

SwingUtilities.invokeLater(new Runnable(){public void run() {
 // your code
}});
于 2012-11-15T22:42:31.577 回答
0

此外,在尝试更新 的模型时JTable,在更新模型之前删除任何内容也很重要tableModelListenermodel.addColumn()我用and看到了这个观察结果table.moveColumn()。确保在tableModelListener对模型进行任何更改之后添加。

于 2014-01-27T03:27:31.537 回答
0

您能否澄清一下如何添加行?希望使用模型,对吗?添加新行后,您必须调用模型的方法 fireTableDataChanged/不是最好的选择/或 fireTableRowsInserted/更好/不要忘记使用 SwingUtilities.invokeLater 来避免问题 Swing

于 2012-11-15T22:44:32.743 回答
-1

我希望你知道 Swing 不是线程安全的(除了少数例外)。您需要在代码中处理好这一点。

于 2012-11-15T22:41:10.290 回答