JTable. Eliminando filas. Consumir el evento para no despacharse más.

Necesitaba eliminar filas de un JTable en la tecla de borrar presionando. Entonces, el caso de uso es bastante simple, el usuario selecciona algunas filas, presiona la tecla eliminar, las filas se eliminan. El código también es muy simple:

DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); int[] selectedRows = table.getSelectedRows(); for (int i = selectedRows.length - 1; i > -1; i--) { tableModel.removeRow(selectedRows[i]); } 

El problema es que una vez finalizada la eliminación escucharemos un pitido (estoy en Windows, un pitido típico de Windows), como cuando presionamos la tecla Eliminar en un cuadro de texto vacío (o cuando el cursor se encuentra al final de la ventana). texto). Lo que sucede es que la pulsación de tecla se envía más lejos al componente de texto que muestra el contenido de texto de la celda (la primera celda después de las eliminadas). El tono es ejecutado por el método DefaultEditorKit $ DeleteNextCharAction # actionPerformed porque no hay ningún carácter delante del punto. Como hack modifico el evento en el oyente:

 e.setKeyCode(KeyEvent.VK_SHIFT) // see JTable#processKeyBinding 

el evento no se reenvía más, así que el pitido desaparece, pero creo que es una mala solución y hay una mejor. ¿Pero cuál es esa mejor solución?

Utilice enlaces de teclas en su lugar …

 InputMap im = table.getInputMap(JTable.WHEN_FOCUSED); ActionMap am = table.getActionMap(); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "DeleteRow"); am.put("DeleteRow", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Delete row"); int row = table.getSelectedRow(); if (row > -1) { DefaultTableModel model = (DefaultTableModel) table.getModel(); model.removeRow(row); } } }); 

(Tomé prestados los datos de mKorbel para mi prueba, por lo que mi prueba estaba usando un DefaultTableModel , tendrá que pasar al modelo que está usando).

Además, si está editando, esto todavía puede disparar, por lo que tendrá que verificar que

  • su núcleo para eliminar filas es incorrecto, debe comenzar con el índice máximo; de lo contrario, se eliminará la fila no seleccionada,

ejemplo de código

 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import javax.swing.table.*; public class RemoveAddRows extends JFrame { private static final long serialVersionUID = 1L; private Object[] columnNames = {"Type", "Company", "Shares", "Price"}; private Object[][] data = { {"Buy", "IBM", new Integer(1000), new Double(80.50)}, {"Sell", "MicroSoft", new Integer(2000), new Double(6.25)}, {"Sell", "Apple", new Integer(3000), new Double(7.35)}, {"Buy", "Nortel", new Integer(4000), new Double(20.00)}, {"Buy", "IBM", new Integer(1000), new Double(80.50)}, {"Sell", "MicroSoft", new Integer(2000), new Double(6.25)}, {"Sell", "Apple", new Integer(3000), new Double(7.35)}, {"Buy", "Nortel", new Integer(4000), new Double(20.00)}, {"Buy", "IBM", new Integer(1000), new Double(80.50)}, {"Sell", "MicroSoft", new Integer(2000), new Double(6.25)}, {"Sell", "Apple", new Integer(3000), new Double(7.35)}, {"Buy", "Nortel", new Integer(4000), new Double(20.00)} }; private JTable table; private DefaultTableModel model; public RemoveAddRows() { model = new DefaultTableModel(data, columnNames) { private static final long serialVersionUID = 1L; @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; table = new JTable(model); table.setPreferredScrollableViewportSize(table.getPreferredSize()); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); JButton button1 = new JButton("Remove all rows"); button1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { int[] selectedRows = table.getSelectedRows(); for (int i = selectedRows.length - 1; i > -1; i--) { model.removeRow(selectedRows[i]); } /*if (model.getRowCount() > 0) { for (int i = model.getRowCount() - 1; i > -1; i--) { model.removeRow(i); } }*/ System.out.println("model.getRowCount() --->" + model.getRowCount()); } }); JButton button2 = new JButton("Add new rows"); button2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { Object[] data0 = {"Buy", "IBM", new Integer(1000), new Double(80.50)}; model.addRow(data0); Object[] data1 = {"Sell", "MicroSoft", new Integer(2000), new Double(6.25)}; model.addRow(data1); Object[] data2 = {"Sell", "Apple", new Integer(3000), new Double(7.35)}; model.addRow(data2); Object[] data3 = {"Buy", "Nortel", new Integer(4000), new Double(20.00)}; model.addRow(data3); System.out.println("model.getRowCount() --->" + model.getRowCount()); } }); JPanel southPanel = new JPanel(); southPanel.add(button1); southPanel.add(button2); add(southPanel, BorderLayout.SOUTH); } public static void main(String[] args) { RemoveAddRows frame = new RemoveAddRows(); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 
  • Soy un usuario de Win y nunca escuché el pitido de Win Platform, tengo que publicar un SSCCE

Este es el código de MadProgrammer, pero lo modifiqué para que funcione con varias filas seleccionadas a la vez en lugar de una por una:

  // Assume table is a JTable instance InputMap inputMap = table.getInputMap(JTable.WHEN_FOCUSED); ActionMap actionMap = table.getActionMap(); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "DeleteRow"); actionMap.put("DeleteRow", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int[] row = table.getSelectedRows(); for (int i = 0; i < row.length; i++) { ((DefaultTableModel) table.getModel()).removeRow(row[i] - i * 1); } } });