java swing jtable indexoutofboundsexception tablemodel

java - JTable eliminación de fila da ArrayOutofBounds excepción-1



swing indexoutofboundsexception (4)

Está cambiando el modelo de tabla dentro de un TableModelListener y eso me parece un poco arriesgado y supone un riesgo de recursión no deseada. Volvería a factorizar tu código para no hacer esto si es posible. Si todavía estás atascado, entonces debes crear y publicar una sscce .

Editar 1

Si hago un sscce de tu código y agrego las instrucciones println:

import javax.swing.*; import javax.swing.border.BevelBorder; import javax.swing.event.*; import javax.swing.table.*; public class ExpenditurePanel extends JPanel implements TableModelListener { private static final long serialVersionUID = 1L; private static TableModel1 model; private JTable table; public ExpenditurePanel() { model = new TableModel1(); table = new JTable(model); table.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null)); table.setRowSelectionAllowed(false); table.setFillsViewportHeight(true); table.setCellSelectionEnabled(true); table.setColumnSelectionAllowed(false); model.addColumn("Name"); model.addColumn("Week"); model.addColumn("Fortnight"); model.addColumn("Month"); model.addColumn("Year"); model.addColumn("Remove"); Object[] default1 = { "Accomodation", "", "", "", "", false }; Object[] default2 = { "Food", "", "", "", "", false }; model.addRow(default1); model.addRow(default2); model.addTableModelListener(this); this.add(new JScrollPane(table)); table.setRowSorter(null); } public static TableModel1 getModel() { return model; } @Override public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); // **** printf added below System.out.printf("[row: %d, column: %d]%n", row, column); model = (TableModel1) e.getSource(); String columnName = model.getColumnName(column); // **** println added below System.out.println("columnName: " + columnName); Object data = model.getValueAt(row, column); if (model.getValueAt(row, column) == Boolean.TRUE) { System.out.println("Condition working"); // *** AIOOBE called here model.removeRow(row); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { ExpenditurePanel panel = new ExpenditurePanel(); JFrame frame = new JFrame("foo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(panel); frame.setLocationRelativeTo(null); frame.pack(); frame.setVisible(true); } }); } } // **** no idea how close this is to your code ***** class TableModel1 extends DefaultTableModel { @Override public Class<?> getColumnClass(int columnIndex) { if (getRowCount() == 0) { return super.getColumnClass(columnIndex); } Object value = getValueAt(0, columnIndex); if (value == null) { return super.getColumnClass(columnIndex); } return value.getClass(); } }

Obtengo esta salida:

[row: 0, column: 5] columnName: Remove Condition working [row: 0, column: -1] columnName: Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 at java.util.Vector.elementAt(Unknown Source) ...... etc ......

Entonces ves que el método tableChanged(...) del oyente modelo se llama dos veces debido a una recursión que ocurre al cambiar el objeto escuchado dentro del oyente, y la segunda vez que se llama, tiene una columna de -1 que causa tu AIOOBE ser arrojado.

Editar 2
Una posible solución es eliminar al oyente antes de realizar el cambio en el modelo y luego volver a agregar el oyente después de realizar el cambio:

public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); System.out.printf("[row: %d, column: %d]%n", row, column); model = (TableModel1) e.getSource(); String columnName = model.getColumnName(column); System.out.println("columnName: " + columnName); Object data = model.getValueAt(row, column); if (model.getValueAt(row, column) == Boolean.TRUE) { System.out.println("Condition working"); model.removeTableModelListener(this); model.removeRow(row); model.addTableModelListener(this); } }

He estado navegando en numerosos sitios sobre esto y probé algunas cosas diferentes, pero estoy perplejo. Estaría agradecido por algo de ayuda. La condición está funcionando y comprueba si se selecciona una casilla de verificación (verdadera), pero pronto como hago model.removeRow (fila) me da este error.

public class ExpenditurePanel extends JPanel implements TableModelListener{ private static final long serialVersionUID = 1L; private static TableModel1 model; private JTable table; public ExpenditurePanel() { model = new TableModel1(); table = new JTable(model); table.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null)); table.setRowSelectionAllowed(false); table.setFillsViewportHeight(true); table.setCellSelectionEnabled(true); table.setColumnSelectionAllowed(false); model.addColumn("Name"); model.addColumn("Week"); model.addColumn("Fortnight"); model.addColumn("Month"); model.addColumn("Year"); model.addColumn("Remove"); Object[] default1 = {"Accomodation","","","","",false}; Object[] default2 = {"Food","","","","",false}; model.addRow(default1); model.addRow(default2); model.addTableModelListener(this); this.add(new JScrollPane(table)); table.setRowSorter(null); } public static TableModel1 getModel(){ return model; } @Override public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); model = (TableModel1) e.getSource(); String columnName = model.getColumnName(column); Object data = model.getValueAt(row, column); if(model.getValueAt(row,column) == Boolean.TRUE){ System.out.println("Condition working"); //this part keeps giving me error. model.removeRow(row); } } }

Esto es lo que arroja:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 at java.util.Vector.elementData(Unknown Source) at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableModel.getValueAt(Unknown Source) at studentBudget.ExpenditurePanel.tableChanged(ExpenditurePanel.java:53) at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source) at javax.swing.table.AbstractTableModel.fireTableRowsDeleted(Unknown Source) at javax.swing.table.DefaultTableModel.removeRow(Unknown Source) at studentBudget.ExpenditurePanel.tableChanged(ExpenditurePanel.java:59) at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source) at javax.swing.table.AbstractTableModel.fireTableCellUpdated(Unknown Source) at javax.swing.table.DefaultTableModel.setValueAt(Unknown Source) at javax.swing.JTable.setValueAt(Unknown Source) at javax.swing.JTable.editingStopped(Unknown Source) at javax.swing.AbstractCellEditor.fireEditingStopped(Unknown Source) at javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(Unknown Source) at javax.swing.DefaultCellEditor.stopCellEditing(Unknown Source) at javax.swing.DefaultCellEditor$EditorDelegate.actionPerformed(Unknown Source) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.JToggleButton$ToggleButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at javax.swing.plaf.basic.BasicTableUI$Handler.repostEvent(Unknown Source) at javax.swing.plaf.basic.BasicTableUI$Handler.mouseReleased(Unknown Source) at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$000(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)


Para elaborar un poco sobre el seguimiento correcto de @Shover y asumir un caso de uso válido como "tenemos una lista de trabajos, si se hace con uno eliminar ese trabajo de la lista":

El problema básico con su oyente es que no verifica con qué tipo de cambio se le notifica: usted está interesado únicamente en la actualización de una columna en particular, no en ninguna otra (por ejemplo, como quitar la fila), que causa el error en la segunda notificación: un modelEvent of typ removed tiene una columna de -1

La solución es agregar el cheque y no hacer nada si el desencadenador no fue una actualización en la columna específica:

@Override public void tableChanged(TableModelEvent e) { if (!TableUtilities.isUpdate(e)) return; ... }

Analizar un TableModelEvent es un poco incómodo (condiciones no totalmente intuitivas, requiere una lectura a fondo del TableModelEvent javadoc) - que soy demasiado flojo para guardarlo en la memoria, así que hay una clase de utilidad en SwingX , las partes relevantes copiadas aquí para su conveniencia:

/** * Returns a boolean indication whether the event represents a * dataChanged type. * * @param e the event to examine. * @return true if the event is of type dataChanged, false else. */ public static boolean isDataChanged(TableModelEvent e) { if (e == null) return false; return e.getType() == TableModelEvent.UPDATE && e.getFirstRow() == 0 && e.getLastRow() == Integer.MAX_VALUE; } /** * Returns a boolean indication whether the event represents a * update type. * * @param e the event to examine. * @return true if the event is a true update, false * otherwise. */ public static boolean isUpdate(TableModelEvent e) { if (isStructureChanged(e)) return false; return e.getType() == TableModelEvent.UPDATE && e.getLastRow() < Integer.MAX_VALUE; } /** * Returns a boolean indication whether the event represents a * insert type. * * @param e the event to examine * @return true if the event is of type insert, false otherwise. */ public static boolean isInsert(TableModelEvent e) { if (e == null) return false; return TableModelEvent.INSERT == e.getType(); } /** * Returns a boolean indication whether the event represents a * structureChanged type. * * @param e the event to examine. * @return true if the event is of type structureChanged or null, false * else. */ public static boolean isStructureChanged(TableModelEvent e) { return e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW; }


Solo hazlo así:

clsController.getTable().setSortable( false ); model.removeRow( selectedModelRow ); clsController.getTable().setSortable( true );

¡y funciona!


Puede verificar su tipo de evento. Al hacerlo, puede omitir el contenido del método tableChanged para agregar y eliminar.

public void tableChanged(TableModelEvent e) { int type = e.getType(); if (type != TableModelEvent.DELETE && type != TableModelEvent.INSERT) { // operation only for update } }