Как оптимизировать обработку событий в Java Swing? - PullRequest
0 голосов
/ 26 июня 2018

Моя программа использует электронную таблицу, такую ​​как 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);
    }
}
...