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