3

我一直在浏览许多有关此的网站并尝试了一些不同的东西,但我很难过。将不胜感激一些帮助。该条件正在检查是否选中了一个复选框(true),但是一旦我执行 model.removeRow(row) 它就会给我这个错误。

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

这就是它抛出的内容:

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)
4

4 回答 4

3

您正在更改 TableModelListener 内部的 TableModel ,这对我来说似乎有点冒险,并且存在不必要的递归风险。如果可能,我会重新考虑您的代码,以免这样做。如果您仍然卡住,那么您应该创建并发布一个sscce


编辑 1

如果我从您的代码中创建一个sscce并添加 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();
   }
}

我得到这个输出:

[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 ......

因此,您会看到模型侦听器的tableChanged(...)方法被调用了两次,原因是由于更改侦听器内部的侦听对象而发生递归,第二次调用它时,它有一个 -1 列,这会导致您的 AIOOBE 被抛出。


编辑 2
一个潜在的解决方案是在对模型进行更改之前删除侦听器,然后在进行更改后重新添加侦听器:

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);
  }
}
于 2013-07-12T22:11:48.200 回答
1

详细说明@Hover 的正确追踪并假设一个有效的用例,例如“我们有一个工作列表,如果完成一个从列表中删除该工作”:

您的侦听器的基本问题是它不检查通知的更改类型:您只对特定列的更新感兴趣,而不对任何其他(例如删除行)感兴趣,这会导致第二个通知的错误:删除的类型为 modelEvent 的列为 -1

解决方案是添加检查,如果触发器不是特定列的更新,则不执行任何操作:

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

分析 TableModelEvent 有点不方便(不是完全直观的条件,需要彻底阅读 TableModelEvent javadoc)——我懒得把它保存在内存中,所以SwingX中有一个实用程序类,为了方便起见,将相关部分复制到这里:

/**
 * 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;
}
于 2013-07-13T09:35:40.623 回答
0

这样做:

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

它有效!

于 2014-06-10T08:40:05.637 回答
0

您可以检查其事件类型。这样做,您可以跳过 tableChanged 方法的内容进行添加和删除。

public void tableChanged(TableModelEvent e) {
    int type = e.getType();

    if (type != TableModelEvent.DELETE && type != TableModelEvent.INSERT) {

    // operation only for update

    }
}
于 2015-05-06T06:36:09.963 回答