1

Редактировать 3: Это не дублирует общие вопросы «У меня есть вопрос об индексировании в моем коде», потому что, как четко указано в ответе, ошибка в широко используемой сторонней библиотеке jide-common, подтвержденной разработчиками, есть ссылка ниже. Эта ошибка была недавно исправлена ​​(после публикации этого вопроса), и многие старые версии библиотеки все еще затронуты. Таким образом, эта информация может быть полезна для других разработчиков, которые наталкиваются на ту же проблему с jide-common.java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 in Jidesoft DocumentPane

У меня возникла проблема с программированием GUI на Java. Я не уверен в конкретном источнике проблемы (все еще не могу понять) - это может быть либо моя ошибка где-то, какой-то неисправный код в jide-компонентах, либо даже что-то не так с фокусом awt/swing или обработкой событий.

Следующий код зависит от

  • com.jidesoft: Jide сетках: 3.5.1
  • com.jidesoft: Jide-компоненты: 3.5.1
  • com.jidesoft: Jide-общий : 3.5.1

Я нашел this hint на Stackoverflow, но после некоторой отладки, кажется мне, что каждая модификация CellEditor и других компонентов производится в EDT.

Чтобы воспроизвести ошибку, вы должны запустить этот пример и открыть вкладку, содержащую CellEditor (она должна быть последней в строке, иначе переполнение индекса не произойдет), затем введите некоторое «неправильное» значение и не удаляя фокус с редактор, нажмите кнопку «x» на одной из предыдущих вкладок. После этого происходит следующая цепочка событий: 1) вкладка закрывается/удаляется, 2) верификатор CellEditor показывает модальное диалоговое окно, которое, в свою очередь, вызывает перерисовку панели вкладок 3) из-за отсутствия (закрытой) вкладки, генерируется исключение ArrayIndexOutOfBounds.

package com.example; 

import com.jidesoft.document.DocumentComponent; 
import com.jidesoft.document.DocumentPane; 
import com.jidesoft.grid.JideTable; 
import com.jidesoft.grid.TableModelWrapperUtils; 
import com.jidesoft.grid.TextFieldCellEditor; 
import com.jidesoft.swing.JideTabbedPane; 

import javax.swing.*; 
import javax.swing.table.DefaultTableModel; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.math.BigDecimal; 
import java.util.Random; 

/** 
* Dependends on: 
* com.jidesoft:jide-grids:3.5.1 
* com.jidesoft:jide-components:3.5.1 
* com.jidesoft:jide-common:3.5.1 
*/ 
public class ModalPopupFailure { 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     frame.setTitle("test"); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     JComponent panel = new ModalPopupFailure().buildPanel(); 
     frame.setContentPane(panel); 
     frame.setBounds(450, 300, 700, 500); 
     frame.setVisible(true); 
    } 

    /** 
    * @return table editor panel 
    */ 
    private JPanel tableTab() { 
     JPanel result = new JPanel(new BorderLayout()); 

     DefaultTableModel model = new DefaultTableModel(1, 1); 
     model.setValueAt(new BigDecimal(0L), 0, 0); 
     JideTable table = new JideTable(model); 
     table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); 

     final int actualCol0 = TableModelWrapperUtils.getActualColumnAt(table.getModel(), 0); 
     CustomCellEditor bdce = new CustomCellEditor(Integer.class); 
     table.getColumnModel().getColumn(actualCol0).setCellEditor(bdce); 

     result.add(table, BorderLayout.CENTER); 
     return result; 
    } 

    /** 
    * @return Main panel with tabs 
    */ 
    private JComponent buildPanel() { 
     JPanel mainPanel = new JPanel(new BorderLayout()); 

     final DocumentPane documentPane = new DocumentPane(); 

     DocumentComponent dc1 = new DocumentComponent(new JLabel("tab1 label"), "aaa"); 
     documentPane.openDocument(dc1); 

     DocumentComponent dc2 = new DocumentComponent(tableTab(), "TABLETAB"); 
     documentPane.openDocument(dc2); 
     documentPane.setActiveDocument("TABLETAB"); 

     documentPane.setTabbedPaneCustomizer(new DocumentPane.TabbedPaneCustomizer() { 
      @Override 
      public void customize(final JideTabbedPane tabbedPane) { 
       tabbedPane.setShowCloseButton(true); 
       tabbedPane.setUseDefaultShowCloseButtonOnTab(false); 
       tabbedPane.setShowCloseButtonOnTab(true); 
      } 
     }); 

     documentPane.setTabPlacement(SwingConstants.TOP); 

     mainPanel.add(documentPane, BorderLayout.CENTER); 
     mainPanel.add(new JButton(new AbstractAction("New tab") { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         Integer randInt = new Random().nextInt(); 
         DocumentComponent newdc = new DocumentComponent(
           new JLabel("Generated tab label " + randInt), 
           Integer.toString(randInt)); 

         documentPane.openDocument(newdc); 
        } 
       }), 
       BorderLayout.NORTH); 
     JLabel decription = new JLabel("<html>Steps to reproduce:<br />" + 
       "TABLETAB should be the last tab<br />" + 
       "The \"correct\" value for cell editor is 777.<br />" + 
       "Enter any \"incorrect\" number, then close any tab standing before TABLETAB.<br />" + 
       "An exception caused by window repaint should be raised by now.<br />" + 
       "If dialog would not be modal, there would be no window repaint triggered.</html>"); 
     mainPanel.add(decription, BorderLayout.SOUTH); 

     return mainPanel; 
    } 

    private class CustomCellEditor extends TextFieldCellEditor { 

     boolean firstTime = true; 

     public CustomCellEditor(Class<?> aClass) { 
      super(aClass); 
      _textField.setInputVerifier(new InputVerifier() { 
       @Override 
       public boolean verify(JComponent input) { 
        boolean valid = "777".equals(_textField.getText()); 
        if (valid) return true; 

        final JDialog dialog = new JDialog(); 
        dialog.setTitle("Exception expected"); 
        dialog.setContentPane(new JLabel("<html>If one of previous tabs was closed, an exception should be raised by now.</html>")); 
        dialog.setLocationRelativeTo(null); 

        dialog.setModal(true); // Switching to false seems to fix the problem 

        dialog.setSize(new Dimension(300, 100)); 
        dialog.setVisible(true); 

        return true; 
       } 
      }); 
     } 

     @Override 
     public boolean stopCellEditing() { 
      System.out.println("Stopping cell edit " + new Random().nextInt() + "in edt: " + SwingUtilities.isEventDispatchThread()); 
      if (firstTime) { 
       firstTime = false; 
       return false; 
      } 

      return _textField.getInputVerifier().shouldYieldFocus(_textField) && super.stopCellEditing(); 
     } 
    } 
} 

Исключение:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 
    at java.util.ArrayList.rangeCheck(ArrayList.java:635) 
    at java.util.ArrayList.get(ArrayList.java:411) 
    at javax.swing.JTabbedPane.getComponentAt(JTabbedPane.java:1224) 
    at com.jidesoft.plaf.vsnet.VsnetJideTabbedPaneUI.paintContentBorder(Unknown Source) 
    at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI.paintContentBorder(Unknown Source) 
    at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI.paint(Unknown Source) 
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161) 
    at javax.swing.JComponent.paintComponent(JComponent.java:779) 
    at javax.swing.JComponent.paint(JComponent.java:1055) 
    at javax.swing.JComponent.paintChildren(JComponent.java:888) 
    at javax.swing.JComponent.paint(JComponent.java:1064) 
    at javax.swing.JComponent.paintChildren(JComponent.java:888) 
    at javax.swing.JComponent.paint(JComponent.java:1064) 
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5232) 
    at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295) 
    at javax.swing.RepaintManager.paint(RepaintManager.java:1249) 
    at javax.swing.JComponent._paintImmediately(JComponent.java:5180) 
    at javax.swing.JComponent.paintImmediately(JComponent.java:4991) 
    at javax.swing.RepaintManager$3.run(RepaintManager.java:808) 
    at javax.swing.RepaintManager$3.run(RepaintManager.java:796) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796) 
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769) 
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718) 
    at javax.swing.RepaintManager.access$1100(RepaintManager.java:62) 
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1677) 
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745) 
    at java.awt.EventQueue.access$300(EventQueue.java:103) 
    at java.awt.EventQueue$3.run(EventQueue.java:706) 
    at java.awt.EventQueue$3.run(EventQueue.java:704) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:715) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:154) 
    at java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:182) 
    at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:221) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:219) 
    at java.awt.Dialog.show(Dialog.java:1082) 
    at java.awt.Component.show(Component.java:1655) 
    at java.awt.Component.setVisible(Component.java:1607) 
    at java.awt.Window.setVisible(Window.java:1014) 
    at java.awt.Dialog.setVisible(Dialog.java:1005) 
    at com.example.ModalPopupFailure$CustomCellEditor$1.verify(ModalPopupFailure.java:124) 
    at javax.swing.InputVerifier.shouldYieldFocus(InputVerifier.java:132) 
    at javax.swing.JComponent$1.acceptRequestFocus(JComponent.java:3589) 
    at java.awt.Component.isRequestFocusAccepted(Component.java:7739) 
    at java.awt.Component.requestFocusHelper(Component.java:7621) 
    at java.awt.Component.requestFocusInWindow(Component.java:7544) 
    at java.awt.Component.transferFocus(Component.java:7842) 
    at java.awt.Component.hide(Component.java:1688) 
    at javax.swing.JComponent.hide(JComponent.java:5585) 
    at java.awt.Component.show(Component.java:1657) 
    at java.awt.Component.setVisible(Component.java:1607) 
    at javax.swing.JComponent.setVisible(JComponent.java:2641) 
    at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI.setVisibleComponent(Unknown Source) 
    at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI$PropertyChangeHandler.propertyChange(Unknown Source) 
    at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335) 
    at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327) 
    at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:263) 
    at java.awt.Component.firePropertyChange(Component.java:8393) 
    at javax.swing.JComponent.putClientProperty(JComponent.java:4103) 
    at javax.swing.JTabbedPane.removeTabAt(JTabbedPane.java:971) 
    at com.jidesoft.swing.JideTabbedPane.removeTabAt(Unknown Source) 
    at com.jidesoft.document.TdiGroup.removeDocument(Unknown Source) 
    at com.jidesoft.document.DocumentPane.a(Unknown Source) 
    at com.jidesoft.document.DocumentPane.a(Unknown Source) 
    at com.jidesoft.document.DocumentPane.a(Unknown Source) 
    at com.jidesoft.document.DocumentPane.a(Unknown Source) 
    at com.jidesoft.document.DocumentPane.closeDocument(Unknown Source) 
    at com.jidesoft.document.DocumentPane.closeSingleDocument(Unknown Source) 
    at com.jidesoft.document.DocumentPane$34.actionPerformed(Unknown Source) 
    at com.jidesoft.plaf.basic.BasicJideTabbedPaneUI$CloseTabAction.actionPerformed(Unknown Source) 
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018) 
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341) 
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402) 
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259) 
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252) 
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289) 
    at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289) 
    at java.awt.Component.processMouseEvent(Component.java:6516) 
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321) 
    at java.awt.Component.processEvent(Component.java:6281) 
    at java.awt.Container.processEvent(Container.java:2229) 
    at java.awt.Component.dispatchEventImpl(Component.java:4872) 
    at java.awt.Container.dispatchEventImpl(Container.java:2287) 
    at java.awt.Component.dispatchEvent(Component.java:4698) 
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832) 
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492) 
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422) 
    at java.awt.Container.dispatchEventImpl(Container.java:2273) 
    at java.awt.Window.dispatchEventImpl(Window.java:2719) 
    at java.awt.Component.dispatchEvent(Component.java:4698) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:747) 
    at java.awt.EventQueue.access$300(EventQueue.java:103) 
    at java.awt.EventQueue$3.run(EventQueue.java:706) 
    at java.awt.EventQueue$3.run(EventQueue.java:704) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) 
    at java.awt.EventQueue$4.run(EventQueue.java:720) 
    at java.awt.EventQueue$4.run(EventQueue.java:718) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:717) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91) 

Там в "extended" version of code с немного отладочной информации добавлены. Я все еще не могу понять причину проблемы, не говоря уже об исправлении. Заранее спасибо.

Edit: метод OK одна вещь, которую я понял теперь, что отображение диалогового окна изнутри проверить() is wrong, according to docs:

проверить метод существует только определить, является ли вход правилен он никогда не должен вызвать диалоговое окно или вызвать другие побочные эффекты. Метод метода shouldYieldFocus проверяет и, если значения недопустимы, устанавливает минимальное или максимальное значение. Метод shouldYieldFocus допускается для возникновения побочных эффектов ...

Поэтому я переместил весь не-проверяющий код в shouldYieldFocus(). Это не решило проблему, но дальнейшая отсрочка dialog.show() с SwingUtilities.invokeLater(), похоже, работает нормально, никаких ошибок ... пока нет.

public CustomCellEditor(Class<?> aClass) { 
    super(aClass); 
    _textField.setInputVerifier(new InputVerifier() { 

     @Override 
     public boolean shouldYieldFocus(JComponent input) { 
      boolean inputOK = verify(input); 
      if (!inputOK) { 
       final ru.esc.erp.core.components.Dialog dialog = new ru.esc.erp.core.components.Dialog(); 
       dialog.setTitle("Exception may be raised"); 
       dialog.setContentPane(new JLabel("<html>Modal dialog opened with yet another delay.</html>")); 
       dialog.setLocationRelativeTo(null); 

       dialog.setModal(true); // false "fixes" the problem 

       dialog.setSize(new Dimension(300, 100)); 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         dialog.setVisible(true); 
        } 
       }); 
      } 
      return inputOK; 
     } 

     @Override 
     public boolean verify(JComponent input) { 
      return "777".equals(_textField.getText()); 
     } 
    }); 
} 

Edit2:gif with captured video

+0

Я еще [упрощен код] (http://pastebin.com/4GqZixm7). Больше не использовать DocumentPane, таблицы и редакторы ячеек. Простое текстовое поле (которое показывает модальный диалог, если проверка завершилась неудачно) на JideTabbedPane. Теперь используйте только oss-библиотеку, чтобы каждый мог запустить этот пример. Но ошибка все еще существует с jide-oss-3.5.1. И то же самое происходит с jide-oss-3.6.16. –

ответ

1

ОК, это было в JideTabbedPaneUI a bug. Я тестировал исправленный jide-oss с моим примером и больше не было исключений (однако теперь есть некоторые некритические сбои пользовательского интерфейса при закрытии вкладки). Исследуется источник проблемы.

EDIT: они исправили эту ошибку позже в 3.6.17:

по Jide Поддержка »Ср 1 февраля 2017 12:10 утра Только так вы знаете, эта ошибка была исправлена ​​в 3.6.17, который был только что выпущен.

Смежные вопросы