JTable - UI在许多插入时冻结

时间:2013-01-09 10:09:58

标签: java swing concurrency jtable event-dispatch-thread

我有一个GUI应用程序,它有几个标签,每个标签都有一个JTable。我的UI类我在以下代码中处理来自Controller的事件,该代码在EDT上运行:

private void processAnalysisResult(AnalysisResult generatedValue) {
    LimitType limit = generatedValue.getMetric().getLimit();
    String limitName = limit.getName();
    int index = tabs.indexOfTab(limitName);
    Component component = tabs.getComponentAt(index);
    JScrollPane scrollPane = (JScrollPane) component;
    JTable table = (JTable) scrollPane.getViewport().getView();
    AnalysisResultTableModel model = (AnalysisResultTableModel) table.getModel();
    model.addRow(generatedValue);
    }
}

每秒有几千个新生成的结果,atm我把它降低到大约10k。即使使用相对较低的值,应用程序也会冻结大约10-20秒,从Jtable处理UI更新。 addRow方法在插入每一行时调用fireTableRowsInserted方法,但这可能会慢吗?

编辑:这是处理事件的代码(从后台处理线程异步调用):

  controller.addAnalysisGenerationListener(new GeneratedValueListener<AnalysisResult>() {
        @Override
        public void valueGenerated(final GeneratedValueEvent<AnalysisResult> event) {
            processEDT(new Runnable() {
                @Override
                public void run() {
                    processAnalysisResult(event.getGeneratedValue());
                }
            });
        }
    });


private void processEDT(Runnable runnable) {
    if (EventQueue.isDispatchThread()) {
        runnable.run();
    } else {
        SwingUtilities.invokeLater(runnable);
    }
}

2 个答案:

答案 0 :(得分:6)

是的,可能会那么慢。 10k不是一个很低的数字。正如您已经注意到addRow()调用fireTableRowsInserted(),后者又通知视图发生了更改并使视图刷新(但在这种情况下,用户看不到它,因为EDT忙于处理下一个结果)。 解决方案之一是在后台线程上执行processAnalysisResult()并通过将最后一行(model.addRow(generatedValue);)传递给SwingUtilities.invokeLater()来在EDT上更新模型。也许它不会快得多,但至少GUI不会冻结20秒。 当然,您也可以使用专门用于此类任务的SwingWorker。 此外,您可以尝试批量更新模型(例如,每次在EDT上将每100个结果添加到模型中),这样可以最大限度地减少屏幕闪烁。

答案 1 :(得分:4)

猜猜AnalysisResultTableModel是DefaultTableModel的实例吗?

尝试添加批处理addRows()方法,而不是逐个添加。 addRow()调用方法

public void insertRow(int row, Vector rowData) {
    dataVector.insertElementAt(rowData, row);
    justifyRows(row, row+1);
    fireTableRowsInserted(row, row);
}

尝试实现类似的东西

public void insertRows(int row, Vector<Vector> rowsData) {
    for () {
        dataVector.insertElementAt(rowData, row);
        justifyRows(row, row+1);
    }

    fireTableRowsInserted(row, row+rowsData.size());
}