我有一个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);
}
}
答案 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());
}