Проблема выбора JComboBox

Я имею в виду принятый ответ на этот пост -

проблема выбора JTree

У меня есть JTree с узлом, содержащим метку и CheckBoxListExComboBox (компонент Jide - JComboBox с флажками). Пользовательский интерфейс отображается правильно, но когда я нажимаю на поле со списком, я получаю следующее исключение:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.rangeCheck(ArrayList.java:638)
at java.util.ArrayList.remove(ArrayList.java:477)
at java.awt.Container.remove(Container.java:1217)
at java.awt.Container.remove(Container.java:1262)
at java.awt.Container.addImpl(Container.java:1096)
at java.awt.Container.add(Container.java:415)
at com.agilent.cgh.ui.test.RendererDispatcher.setContents(RendererDispatcher.java:119)
at com.agilent.cgh.ui.test.RendererDispatcher.getTreeCellRendererComponent(RendererDispatcher.java:41)
at javax.swing.plaf.basic.BasicTreeUI.paintRow(BasicTreeUI.java:1536)
at javax.swing.plaf.basic.BasicTreeUI.paint(BasicTreeUI.java:1224)
at javax.swing.plaf.metal.MetalTreeUI.paint(MetalTreeUI.java:169)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:777)
at javax.swing.JComponent.paint(JComponent.java:1053)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1532)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1455)
at javax.swing.RepaintManager.paint(RepaintManager.java:1252)
at javax.swing.JComponent._paintImmediately(JComponent.java:5165)
at javax.swing.JComponent.paintImmediately(JComponent.java:4976)
at javax.swing.RepaintManager$3.run(RepaintManager.java:811)
at javax.swing.RepaintManager$3.run(RepaintManager.java:794)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:794)
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:1680)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
at java.awt.EventQueue.access$400(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.awt.EventQueue$3.run(EventQueue.java:691)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:714)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Ниже мой код -

public class JComboBoxJTree2 {
  public JComponent makeUI() {
    String[] m = {"Running", "Paused", "Stopped"};
    DefaultMutableTreeNode root = new DefaultMutableTreeNode(new Node("Plugins"));
    root.add(new DefaultMutableTreeNode(new Node("Plugin 1", m)));
    root.add(new DefaultMutableTreeNode(new Node("Plugin 2", m)));
    DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(new Node("Plugin 3", m));
    root.add(leaf);
    leaf.add(new DefaultMutableTreeNode(new Node("Plugin 3A", m)));
    leaf.add(new DefaultMutableTreeNode(new Node("Plugin 3B", m)));

    JTree tree = new JTree(root);

    CheckBoxListExComboBox workflows=new CheckBoxListExComboBox();

    /*RendererDispatcher rendererDispatcher = new RendererDispatcher(new JComboBox<String>());
    RendererDispatcher editorDispatcher = new RendererDispatcher(new JComboBox<String>());*/


   /* RendererDispatcher rendererDispatcher = new RendererDispatcher(new CheckBoxListExComboBox());
    RendererDispatcher editorDispatcher = new RendererDispatcher(new CheckBoxListExComboBox());*/

    RendererDispatcher rendererDispatcher = new RendererDispatcher(workflows);
    RendererDispatcher editorDispatcher = new RendererDispatcher(workflows);


    tree.setCellRenderer(rendererDispatcher);
    tree.setCellEditor(editorDispatcher);
    tree.setEditable(true);

    return new JScrollPane(tree);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new JComboBoxJTree2().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}







import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.EventObject;

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;

import com.jidesoft.combobox.CheckBoxListExComboBox;

class RendererDispatcher extends DefaultCellEditor implements TreeCellRenderer {
      private final JPanel panel = new JPanel();
      private final JLabel pluginName = new JLabel();
      //private final JComboBox<String> comboBox;
      private final CheckBoxListExComboBox comboBox;
      private Node node;

      public RendererDispatcher(CheckBoxListExComboBox comboBox) {
        super(comboBox);
        this.comboBox = comboBox;
        panel.setOpaque(false);
        panel.add(pluginName);
        panel.add(comboBox);
      }
      @Override public Component getTreeCellRendererComponent(
          JTree tree, Object value, boolean selected, boolean expanded,
          boolean leaf, int row, boolean hasFocus) {
        Node node = extractNode(value);
        setContents(node);
        return panel;
      }
      @Override public Component getTreeCellEditorComponent(
          JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
        Node node = extractNode(value);
        setContents(node);
        this.node = node;
        return panel;
      }
      @Override public Object getCellEditorValue() {
        Object o = super.getCellEditorValue();
        DefaultComboBoxModel<String> m = (DefaultComboBoxModel<String>) comboBox.getModel();
        Node n = new Node(pluginName.getText(), node.getPlugins());
        //n.setSelectedPluginIndex(m.getIndexOf(o));
        n.setSelectedIndices(comboBox.getSelectedIndices());
        return n;
      }
      @Override public boolean isCellEditable(final EventObject event) {
        Object source = event.getSource();
        if (!(source instanceof JTree) || !(event instanceof MouseEvent)) {
          return false;
        }
        final JTree tree = (JTree) source;
        final MouseEvent mouseEvent = (MouseEvent) event;
        final TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
        if (path == null) {
          return false;
        }
        Object node = path.getLastPathComponent();
        if (node == null || !(node instanceof DefaultMutableTreeNode)) {
          return false;
        }

        Rectangle r = tree.getPathBounds(path);
        if (r == null) {
          return false;
        }
        Dimension d = panel.getPreferredSize();
        r.setSize(new Dimension(d.width, r.height));
        if (r.contains(mouseEvent.getX(), mouseEvent.getY())) {
          EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
              Point pt = SwingUtilities.convertPoint(tree, mouseEvent.getPoint(), panel);
              //System.out.println(pt);
              Object o = SwingUtilities.getDeepestComponentAt(panel, pt.x, pt.y);
              if (o instanceof JComboBox) {
                comboBox.showPopup();
              } else if (o instanceof Component) {
                Object oo = SwingUtilities.getAncestorOfClass(JComboBox.class, (Component) o);
                if (oo instanceof JComboBox) {
                  comboBox.showPopup();
                }
              }
            }
          });
          return true;
        }
        return delegate.isCellEditable(event);
      }
      private static Node extractNode(Object value) {
        if (value instanceof DefaultMutableTreeNode) {
          DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
          Object userObject = node.getUserObject();
          if (userObject instanceof Node) {
            return (Node) userObject;
          }
        }
        return null;
      }
      private void setContents(Node node) {
        if (node == null) {
          return;
        }
        pluginName.setText(node.toString());
        DefaultComboBoxModel<String> model = (DefaultComboBoxModel<String>) comboBox.getModel();
        model.removeAllElements();
        if (node.getPlugins().length > 0) {
          panel.add(comboBox);
          for (String s : node.getPlugins()) {
            model.addElement(s);
          }
          //comboBox.setSelectedIndex(node.getSelectedPluginIndex());
          comboBox.setSelectedIndices(node.getSelectedIndices());

        } else {
          panel.remove(comboBox);
        }
      }
    }












class Node {
      private final String name;
      private final String[] plugins;
      private int selectedPluginIndex;
      private int [] selectedIndices={0};
      public Node(String name, String... plugins) {
        this.name = name;
        this.plugins = plugins;
      }
      public String toString() {
        return name;
      }
      public int getSelectedPluginIndex() {
        return selectedPluginIndex;
      }
      public void setSelectedPluginIndex(int selectedPluginIndex) {
        this.selectedPluginIndex = selectedPluginIndex;
      }
      public String[] getPlugins() {
        return plugins;
      }
    public int[] getSelectedIndices() {
        return selectedIndices;
    }
    public void setSelectedIndices(int[] selectedIndices) {
        if(selectedIndices!=null){
            this.selectedIndices = selectedIndices;
        }

    }
}

Я понимаю, что код пытается получить доступ к несуществующему индексу, но не знаю, как решить эту проблему. может ли кто-нибудь помочь мне в этом? Спасибо за помощь.


person Akshay Panchakshari    schedule 26.05.2017    source источник
comment
Зачем вам нужно добавлять/удалять поле со списком? Поле со списком может быть добавлено дважды. Можете ли вы сделать его скрытым вместо этого?   -  person Sam    schedule 26.05.2017
comment
Предполагая, что вы говорите о методе setContents(), даже я запутался в этом, потому что он добавляется в сам конструктор, но если я не добавлю его туда, он просто не отображается в пользовательском интерфейсе. Отображается только метка. Я не уверен, что здесь будет делать скрытие поля со списком, оно все равно будет добавлено, верно?   -  person Akshay Panchakshari    schedule 26.05.2017
comment
Также этот код отлично работает, если я передаю два разных объекта со списком средству визуализации в методе makeUI(). (см. закомментированный код).   -  person Akshay Panchakshari    schedule 26.05.2017