Исключение ArrayIndexOutOfBoundsException: -1 при создании JTable / tablechanged

#java #multithreading #swing #jtable #abstracttablemodel

#java #многопоточность #качать #jtable #abstracttablemodel

Вопрос:

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

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

РЕДАКТИРОВАТЬ: я включил несколько syso s в AnnoTable раздел непосредственно перед tableChanged вызовом, и они не отображаются в консоли, поэтому я думаю, что проблема должна возникнуть еще до того, как приложение дойдет до этой точки, т. Е. Либо при его вызове, AAView либо при создании экземпляра модели данных и таблицы…

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

ПРАВКА III: * Я решил проблему. Мне нужно было создать экземпляр другого объекта из AnnoData , передать его в новый экземпляр AnnoTableModel , установить этот экземпляр в мою таблицу, а ЗАТЕМ fireTableDataChanged() .

ПРАВКА IV: Хорошо, так fireTableDataChanged() что (как используется в ПРАВКЕ III) в конце концов не нужно. Я все равно хотел бы использовать его, а не постоянно создавать новые объекты. Думаю, я должен задать новый вопрос… Спасибо!

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

Ответ №1:

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

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

Комментарии:

1. @kleopatra: Спасибо. Конечно, в моем случае setModel() вызывался бы мой жестко tableChanged() закодированный (см. РЕДАКТИРОВАНИЕ II), который ожидал получить параметры, которые он не получил. Я удалил метод. Таблица теперь отображается правильно, но всякий раз, когда что-то изменяется annoData (с помощью метода, который также выполняется ((AbstractTableModel)aaView.getAnnoTable().getModel()).fireTableDataChanged() после того, как все установлено annoData ), таблица по-прежнему не обновляется… Возможно, это следует задать в новом запросе, если только у кого-то здесь нет быстрого ответа :). Спасибо всем!

2. не вызывайте ни один из методов fireXX модели из любого кода, внешнего по отношению к модели. Вместо этого реализуйте модель , чтобы делать это, когда что-либо изменилось

3. @kleopatra: я решил проблему (см. РЕДАКТИРОВАНИЕ III), создав другой экземпляр AnnoData (который компилирует a Vector из Vector s и a 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); 
  

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

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

Комментарии:

1. неправильно — две верхние строки не связаны с исключением (см. Трассировку стека 🙂 Кроме того, анализ верен: код прослушивателя должен защищать от «специальных значений» (HEADER_ROW, ALL_COLUMNS) в индексе строки / столбца

Ответ №4:

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

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

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

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

Ответ №5:

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

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