JTable - UI在许多插入时冻结

Bob*_*r02 0 java concurrency swing jtable event-dispatch-thread

我有一个GUI应用程序,它有几个选项卡,每个选项卡都有一个JTable.我的UI类i在以下代码中处理来自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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*yga 6

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