You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JTable监听器触发次数过多问题求助(代码重复执行)

问题根源与解决办法

我一眼就看出问题所在了——你在循环添加表格行的过程中重复注册了鼠标监听器!看你的cargarProductos方法,for (Producto p : productos)这个循环里,每迭代一次就给tabProductos加一次MouseListener,表格有多少行,就会注册多少个相同的监听器。这样每次触发点击事件时,所有注册的监听器都会执行一遍,自然会打印多次idProducto,还会拖慢程序运行速度。

另外你的ListSelectionListener也有两个问题:一是如果这个监听器也是在循环里注册的(你贴的代码里没显示,但最好统一处理),也会出现重复执行的情况;二是没有正确用getValueIsAdjusting()来过滤选择过程中的中间事件。

具体修复步骤:

1. 把监听器注册移到循环外面

所有监听器的添加操作都应该放在表格行全部添加完成之后,绝对不能放在遍历添加行的循环里!这样只会注册一次监听器,事件触发时也只会执行一次。

2. 正确处理ListSelectionListener的事件

valueChanged方法里,先判断e.getValueIsAdjusting()是否为false,这能确保只有当选择操作完全结束时才执行代码,避免选择过程中多次触发事件。

修正后的完整代码:

public void cargarProductos(ArrayList<Producto> productos) {
    DefaultTableModel tm = new DefaultTableModel() {
        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }
    };
    String[] cabecera = {"ID", "Nombre", "Detalle", "Precio Unit.", "idP", "Proveedor"};
    tm.setColumnIdentifiers(cabecera);
    
    // 先批量添加所有行到表格模型
    for (Producto p : productos) {
        Object[] row = {p.getId(), p.getNombre(), p.getTamaño(), p.getPrecioUnitario(), 
                        p.getProveedor().getId(), p.getProveedor().getNombre()};
        tm.addRow(row);
    }
    
    // 设置表格模型
    tabProductos.setModel(tm);
    
    // --- 所有监听器注册都放在这里,仅执行一次 ---
    // 鼠标双击监听器
    tabProductos.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            // 增加非空判断,避免空指针
            if (e.getClickCount() == 2 && !tabProductos.getSelectionModel().isSelectionEmpty()) {
                int idProducto = (int) tabProductos.getValueAt(tabProductos.getSelectedRow(), 0);
                System.out.println(idProducto);
                asignarProdcuto(idProducto);
            }
        }
    });
    
    // 列表选择监听器
    tabProductos.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            // 过滤调整中的中间事件,只处理最终选择完成的事件
            if (!e.getValueIsAdjusting() && !tabProductos.getSelectionModel().isSelectionEmpty()) {
                int idProducto = (int) tabProductos.getValueAt(tabProductos.getSelectedRow(), 0);
                System.out.println(idProducto);
                asignarProdcuto(idProducto);
            }
        }
    });
    
    // 表格的其他配置也统一放在循环外
    tabProductos.getColumn("ID").setMaxWidth(36);
    tabProductos.setAutoCreateRowSorter(true);
    tabProductos.getTableHeader().setReorderingAllowed(false);
}

额外提醒:

  • 如果之前在其他地方也注册过相同的监听器,记得移除重复注册,避免重复执行逻辑。
  • 后续如果需要更新表格数据,建议直接更新DefaultTableModel的内容,而不是重新创建模型并重复注册监听器。

内容的提问来源于stack exchange,提问作者John Il Piero

火山引擎 最新活动