首页 > 解决方案 > 如何优化 Java Swing 中的事件处理?

问题描述

我的程序使用像 JTable 这样的具有数千行的电子表格。如果用户更改了一个单元格值,事件侦听器会执行一些昂贵的侦听器函数。每次执行只需不到一秒钟。

但是像在列中“全部替换”这样的操作会导致很长的延迟,因为事件侦听器会为每个更改的行执行一次。

如何优化侦听器的执行?

(我认为,在“全部替换”等操作期间,所有表侦听器事件都应该以某种方式停用,并且应该在最后执行一次。理想情况下,我不想单独调整每个侦听器。)

以下代码显示了该问题。使用“填充表格”按钮,一个函数会用数字填充除最后一个单元格之外的每个单元格。表侦听器对每个单元格更改执行求和操作。因为这个计算很快,我插入了一个 Thread.sleep 函数来模拟一个昂贵的操作。按“填充表”后,程序会挂起几秒钟。

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);
    }
}

标签: javaswingjtablelistener

解决方案


推荐阅读