ArrayIndexOutOfBoundsException: -1 при создании/изменении таблицы JTable

Я прочитал все темы, которые выглядели так, как будто они могут решить мою проблему, и я также прочитал все ответы здесь, но я все еще не в своем уме. Я не уверен, почему возникает исключение, хотя у меня есть ощущение, что это может быть связано с threading. Если это так, пожалуйста, дайте мне знать, где включить new Runnable()и нужно ли invokeLater() или invokeAndWait(), поскольку я пробовал это безрезультатно.

Пожалуйста, потерпите меня, пока я дам вам код, который приводит к исключению + трассировка стека (ниже).

EDIT: я включил несколько syso в раздел AnnoTable непосредственно перед вызовом tableChanged, и они не отображаются в консоли, поэтому я думаю, что проблема должна возникнуть еще до того, как приложение доберется до этого точка, то есть либо при вызове из AAView, либо при создании экземпляра данных и модели таблицы...

EDIT II: проблема заключалась в перезаписанном методе tableChanged. Это, очевидно, вызовет исключение. Я также удалил вызов tableChanged() (который не имеет значения). Теперь у меня другая проблема: понять, как изменение базовых данных (AnnoData) может автоматически обновлять таблицу. Хотя это, возможно, для другого запроса (после расширенного поиска в Google), не стесняйтесь публиковать полезные комментарии в этой ветке, так как я продолжу ее читать... БОЛЬШОЕ СПАСИБО за все полезные комментарии и советы!

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, содержащий три Vector<Object> и 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. Но поскольку я хотел fireTableDataChanged из класса, который знал только AAView (который также имеет метод setAnnoTable()), я хотел сделать это правильно, тогда как раньше это работало просто отлично. Закон Мерфи?


person s.d    schedule 24.10.2011    source источник


Ответы (5)


Значение rowIndex, равное -1 (==TableModelEvent.HEADER_ROW), указывает на то, что структура модели полностью изменилась. Такое событие запускается внутри JTable на setModel. Прочтите API-документ TableModelEvent, чтобы полностью понять, какие типы/значения следует ожидать в tableChanged слушателя.

Кстати, @AKJ прав - не нужно запускать какие-либо события TableModelEvents в коде вашей таблицы. Заставьте модель запускать события по мере необходимости.

person kleopatra    schedule 24.10.2011
comment
@kleopatra: Спасибо. Конечно, в моем случае setModel() вызовет мой жестко запрограммированный tableChanged() (см. EDIT II), который ожидал получить параметры, которые он не получил. Я удалил метод. Теперь таблица отображается правильно, но всякий раз, когда что-то изменяется в annoData (с помощью метода, который также выполняет ((AbstractTableModel)aaView.getAnnoTable().getModel()).fireTableDataChanged() после того, как все установлено в annoData), таблица по-прежнему не обновляется... Возможно, это следует задать в новом запросе, ЕСЛИ у кого-то здесь нет быстрого ответа :). Спасибо всем! - person s.d; 26.10.2011
comment
не вызывайте какие-либо методы fireXX модели из любого кода, внешнего по отношению к модели. Вместо этого реализуйте модель, чтобы делать это, когда что-то изменилось. - person kleopatra; 26.10.2011
comment
@kleopatra: я решил проблему (см. РЕДАКТИРОВАТЬ III), создав еще один экземпляр AnnoData (который компилирует Vector из Vectors и String[] из базовой модели XML), создал новый экземпляр модели (передав новый объект AnnoData в это), установить новую модель на стол и fireTableDataChanged() на модель (только что выяснил, что последняя не нужна). Есть ли способ избежать создания экземпляра нового объекта AnnoData и повторного выполнения действий? Как можно было бы использовать fireTableDataChanged() в этом контексте? Но, возможно, это все-таки для нового запроса... - person s.d; 26.10.2011

Это означает, что вы передаете -1 как строку или столбец. Это не разрешено - убедитесь, что вы передаете правильное значение.

person Bozho    schedule 24.10.2011

У меня такое ощущение, что ваша проблема здесь:

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

Поскольку вы не указали значение row или column, вызовы getColumn() и getRow() вернут -1, которое вы затем передадите getValueAt().

Попробуйте посмотреть конструктор для TableModelEvent. У него есть параметры для указания этих значений строки/столбца.

person BenCole    schedule 24.10.2011
comment
неправильно - две верхние строки не связаны с исключением (см. трассировку стека :-) Кроме того, анализ верен: код слушателя должен защищать от "специальных значений" (HEADER_ROW, ALL_COLUMNS) в индексе строки/столбца - person kleopatra; 24.10.2011

TableModelEvent tme = new TableModelEvent(tableModel);
this.tableChanged(tme);

Я не вижу необходимости в этом звонке. Как указывают другие плакаты, это причина вашей проблемы.

Если вы правильно реализуете модель таблицы, всякий раз, когда вы обновляете модель таблицы, jtable будет автоматически получать уведомления, и вам также не нужно писать метод tableChanged(). Итак, я потерялся, почему вам нужно явно вызывать tableChanged().

Всякий раз, когда вы хотите обновить таблицу, просто обновите модель. Также на первый взгляд кажется, что нет никаких проблем с потоками.

person Ashwinee K Jha    schedule 24.10.2011

Ваш конструктор AnnoTable пропускает ссылки на не полностью сконструированный объект «этот». Кроме того, регистрация Listeners из конструктора небезопасна. введите здесь описание ссылки

Создавайте свои объекты, выполняя как можно меньше работы в конструкторе, а затем работайте с полностью построенными объектами. Добавьте слушателей, настройте модели, fireEvents и т. д.

person Ryan    schedule 08.07.2014