Моя программа использует электронную таблицу, такую как JTable, с тысячами строк. Если пользователь изменяет значение одной ячейки, прослушиватели событий выполняют некоторые дорогостоящие функции прослушивателя. Каждое выполнение занимает менее секунды.
Но такие операции, как «заменить все» в столбце, вызывают большую задержку, поскольку прослушиватели событий выполняются один раз для каждой измененной строки.
Как я могу оптимизировать исполнение слушателей?
(Я думаю, что все события прослушивателя таблицы должны быть каким-то образом деактивированы во время операций, таких как «заменить все», и должны выполняться один раз в конце. В идеале я не хочу адаптировать каждого слушателя отдельно.)
Следующий код показывает проблему. С помощью кнопки «Заполнить таблицу» функция заполняет каждую ячейку, кроме последней, номером. Слушатель таблицы выполняет операцию суммирования для каждого изменения ячейки. Поскольку эти вычисления быстрые, я вставил функцию Thread.sleep для имитации дорогостоящей операции. Программа зависает через несколько секунд после нажатия «Fill Table».
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
public class TableListenerExample {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TableListenerExample().startGUI();
}
});
}
public void startGUI() {
JFrame tableFrame = new JFrame();
tableFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tableFrame.setTitle("Table Example");
tableFrame.setSize(700, 860);
tableFrame.setLocationRelativeTo(null);
Object[][] data = new Object[100][1];
String[] columnNames = {"Column 1"};
JTable exampleJTable = new JTable(data, columnNames);
JScrollPane sp = new JScrollPane(exampleJTable);
TableModel tabModel = exampleJTable.getModel();
// the example uses only one table model listener event
tabModel.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getFirstRow() == e.getLastRow() && e.getLastRow() == tabModel.getRowCount() - 1) {
// ignore changes in the sum cell
return;
}
TableModel tabModel = exampleJTable.getModel();
Object cellValue;
Integer cellValueI;
Integer total = 0;
// calculate a sum of all cells
for (int i = 0; i < tabModel.getRowCount() - 1; i++) {
cellValue = tabModel.getValueAt(i, 0);
cellValueI = 0;
try {
cellValueI = Integer.parseInt((String) cellValue);
} catch (NumberFormatException ex) {
//ignore
}
total += cellValueI;
}
try {
// simulate the time delay for a bigger calculation
Thread.sleep(100);
} catch (InterruptedException ex) {
// ignore
}
// write the sum in the last cell
tabModel.setValueAt("Sum: " + total, tabModel.getRowCount() - 1, 0);
}
});
tableFrame.add(sp, BorderLayout.CENTER);
JButton fillButton = new JButton("Fill Table");
tableFrame.add(fillButton, BorderLayout.SOUTH);
fillButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TableModel tabModel = exampleJTable.getModel();
for (int i = 0; i < tabModel.getRowCount() - 1; i++) {
tabModel.setValueAt(Integer.toString(i + 1), i, 0);
}
}
});
tableFrame.setVisible(true);
}
}