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




