【问题标题】:ArrayIndexOutOfBoundsException: -1 on JTable creation/tablechangedArrayIndexOutOfBoundsException:在 JTable 创建/表更改时为 -1
【发布时间】:2011-10-24 13:08:04
【问题描述】:

我已经阅读了所有看起来好像可以解决我的问题的线程,并且我也阅读了这里的所有答案,但我仍然无能为力。我不确定为什么会抛出异常,尽管我觉得这可能与threading 有关。如果有,请告诉我在哪里添加 new Runnable() 以及是 invokeLater() 还是 invokeAndWait(),因为我已经尝试过了。

请耐心等待我给你导致异常的代码+堆栈跟踪(下)。

编辑:在调用tableChanged 之前,我在AnnoTable 部分中包含了一些sysos,它们没有出现在控制台中,因此我认为问题必须在应用程序到达该点之前发生,即从AAView 调用它或实例化数据和表模型时......

EDIT II:问题是被覆盖的tableChanged 方法。这显然会引发异常。我也删除了tableChanged() 调用(这不会产生影响)。现在我遇到了另一个问题:了解基础数据 (AnnoData) 的更改如何自动更新表。虽然这可能是另一个查询(在扩展的 Google 搜索之后),但请随时在此线程中发布有用的 cmets,因为我会继续阅读它......非常感谢所有有用的 cmets 和提示!

EDIT III:* 我已经解决了这个问题。我需要从AnnoData 实例化另一个对象,将其传递给AnnoTableModel 的新实例,将此实例设置为我的表,然后fireTableDataChanged()

EDIT IV: 好的,所以 fireTableDataChanged()(在 EDIT III 中使用)毕竟是不必要的。我仍然想使用它而不是一直创建新对象。我想我应该问一个新问题...谢谢!

AAView 中的这个方法应该创建一个扩展JTable 的对象,将其放入JScrollPane,等等(后者确实有效)。

private JPanel createAnnoTablePanel() {
    annoTablePanel = new JPanel();
    annoTable = new AnnoTable(aameth);
    setAnnoTable(annoTable);
    JScrollPane scrollPane = new JScrollPane(getAnnoTable());
    annoTablePanel.add(scrollPane);
    return annoTablePanel;
}

这是AnnoTable 类(aameth 是一个实例对象,包含访问数据模型的业务逻辑,工作正常)。

public class AnnoTable extends JTable implements TableModelListener
{

  public AnnoTable(AAMethods aameth)
  {

     int tokenCount = aameth.getTokenCount();

     AnnoData annoData = new AnnoData(aameth); // cf. below, AnnoData is a Vector(Vector<Object>,String[])

     TableModel tableModel = new AnnoTableModel(annoData.getAnnoData(),
     // AnnoTableModel extends AbstractTableModel(Vector, String[])
     annoData.getColTitles());
     setModel(tableModel);
     getModel().addTableModelListener(this);
     TableModelEvent tme = new TableModelEvent(tableModel);
     this.tableChanged(tme);
     setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     setCellSelectionEnabled(true);
     getColumnModel().getSelectionModel().addListSelectionListener(new AnnoTableSelectionListener(this));
     setPreferredScrollableViewportSize(this.getPreferredSize());

  }

  public void tableChanged(TableModelEvent e) {
  int row = e.getFirstRow();
     int column = e.getColumn();
     AbstractTableModel model = (AbstractTableModel)e.getSource();
     String columnName = model.getColumnName(column);
     Object data = model.getValueAt(row, column); // This is where the exception is thrown!
  }
}

如果您需要AnnoTableModel()(这是AbstractTableModel 的相当通用的扩展)或AnnoData(构造一个包含三个Vector&lt;Object&gt;Vector 和一个用于列标题的String[])的源代码,请告诉我。

这是堆栈跟踪。

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.Vector.elementAt(Unknown Source)
at javax.swing.table.DefaultTableModel.getValueAt(Unknown Source)
at package.AnnoTable.tableChanged(AnnoTable.java:52)
at javax.swing.JTable.setModel(Unknown Source)
at javax.swing.JTable.<init>(Unknown Source)
at javax.swing.JTable.<init>(Unknown Source)
at package.AnnoTable.<init>(AnnoTable.java:25)
at package.AAView.createAnnoTablePanel(AAView.java:464)
at package.AAView.createNorthPanel(AAView.java:455)
at package.AAView.displayAndAnnotate(AAView.java:444)
at package.AAView.loadProject(AAView.java:333)
at package.AAView.actionPerformed(AAView.java:286)
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.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.AbstractButton.doClick(Unknown Source)
at javax.swing.AbstractButton.doClick(Unknown Source)
at javax.swing.plaf.basic.BasicMenuItemUI$Actions.actionPerformed(Unknown Source)
at javax.swing.SwingUtilities.notifyAction(Unknown Source)
at javax.swing.JComponent.processKeyBinding(Unknown Source)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(Unknown Source)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(Unknown Source)
at javax.swing.JMenuBar.processBindingForKeyStrokeRecursive(Unknown Source)
at javax.swing.JMenuBar.processKeyBinding(Unknown Source)
at javax.swing.KeyboardManager.fireBinding(Unknown Source)
at javax.swing.KeyboardManager.fireKeyboardAction(Unknown Source)
at javax.swing.JComponent.processKeyBindingsForAllComponents(Unknown Source)
at javax.swing.JComponent.processKeyBindings(Unknown Source)
at javax.swing.JComponent.processKeyEvent(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.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(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$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.awt.EventQueue$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$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)

我可以在那里看到EDT,所以据我所知,这可能真的是线程问题。但是,我不知道如何找出应该从哪里开始新的Thread(或调用new Runnable()

附带说明,只有当我将 AnnoTable 更改为扩展 JTable 而不是 JPanel 时,异常才开始出现。最初我让AnnoTable 不仅构建了表格,而且将其包装在滚动窗格中并将其添加到新的JPanel。但是因为我想从一个只知道AAView 的类中fireTableDataChanged(它还具有setAnnoTable() 方法),所以我想以正确的方式进行操作,而之前它工作得很好。墨菲定律?

【问题讨论】:

    标签: java multithreading swing jtable abstracttablemodel


    【解决方案1】:

    -1 的 rowIndex (==TableModelEvent.HEADER_ROW) 表示模型的结构已经完全改变。此类事件由 setModel 上的 JTable 在内部触发。阅读 TableModelEvent 的 api 文档以充分了解侦听器的 tableChanged 中期望的类型/值。

    顺便说一句,@AKJ 是对的——无需在表格代码中触发任何 TableModelEvents。使 model 触发适当的事件

    【讨论】:

    • @kleopatra:谢谢。当然,在我的情况下,setModel() 会调用我的硬编码tableChanged()(参见 EDIT II),它期望接收它没有收到的参数。我已经删除了该方法。该表现在可以正确显示,但是每当在 annoData 中更改某些内容时(通过在 ((AbstractTableModel)aaView.getAnnoTable().getModel()).fireTableDataChanged() 中设置所有内容后也执行 annoData 的方法),该表仍然没有更新...也许应该问一下不过,在一个新的查询中,除非这里有人有一个快速的答案:)。谢谢大家!
    • 不要从模型外部的任何代码调用模型的任何 fireXX 方法。而是实现 model 以在发生任何变化时这样做
    • @kleopatra:我已经通过创建另一个AnnoData 实例解决了这个问题(参见EDIT III)(它编译了Vectors 的Vector 和来自一个String[]底层 XML 模型),创建了一个新的模型实例(将新的AnnoData 对象传递给它),将新模型设置到表中并在模型上设置fireTableDataChanged()(刚刚发现后者是不必要的)。 有没有办法避免实例化一个新的AnnoData 对象并再次执行这些动作?在这种情况下如何使用fireTableDataChanged() 但也许这毕竟是一个新查询......
    【解决方案2】:

    这意味着您将-1 作为行或列传递。这是不允许的 - 请确保您传递了正确的值。

    【讨论】:

      【解决方案3】:

      我感觉你的问题就在这里:

      TableModelEvent tme = new TableModelEvent(tableModel);      
      this.tableChanged(tme); 
      ->
        int column = e.getColumn();     
        AbstractTableModel model = (AbstractTableModel)e.getSource();     
        String columnName = model.getColumnName(column); 
      

      因为您没有指定rowcolumn 值,所以getColumn()getRow() 调用将返回-1,然后您将其传递给getValueAt()

      尝试查看TableModelEvent 的构造函数。它具有用于指定这些行/列值的选项。

      【讨论】:

      • 错误 - 上面两行与异常无关(参见堆栈跟踪 :-) 除此之外,分析是正确的:侦听器代码必须防范“特殊值”(HEADER_ROW,ALL_COLUMNS)行/列索引
      【解决方案4】:
      TableModelEvent tme = new TableModelEvent(tableModel);
      this.tableChanged(tme);
      

      我认为不需要这个电话。正如其他海报所指出的那样,这是您的问题的原因。

      如果你正确地实现了表模型,每当你更新表模型时,jtable 会自动收到通知,你也不需要编写 tableChanged() 方法。所以我不知道为什么需要显式调用 tableChanged()。

      只要您想更新表格,只需更新模型即可。乍一看,似乎没有涉及任何线程问题。

      【讨论】:

        【解决方案5】:

        您的 AnnoTable 构造函数正在泄漏对未完全构造的“this”对象的引用。此外,从构造函数注册侦听器也不安全。 enter link description here

        在构造函数中尽可能少地构建对象,然后对完全构建的对象进行操作。添加监听器、调整模型、fireEvents 等...

        【讨论】:

          猜你喜欢
          • 2014-06-06
          • 2012-10-20
          • 2015-12-13
          • 2021-12-19
          • 2020-02-07
          • 2012-12-23
          • 1970-01-01
          • 2020-03-27
          • 1970-01-01
          相关资源
          最近更新 更多