Java Swing How to - Create JComboBox JTree renderer and editor








Question

We would like to know how to create JComboBox JTree renderer and editor.

Answer

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.EventObject;
//w w w  . jav a2s. co  m
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;

public class Main {
  public static void main(String[] args) {
    String[] m = { "A", "B", "C" };
    DefaultMutableTreeNode root = new DefaultMutableTreeNode(
        new Node("Values"));
    root.add(new DefaultMutableTreeNode(new Node("Value 1", m)));
    root.add(new DefaultMutableTreeNode(new Node("Value 2", m)));
    DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(new Node(
        "Value 3", m));
    root.add(leaf);
    leaf.add(new DefaultMutableTreeNode(new Node("Value 3A", m)));
    leaf.add(new DefaultMutableTreeNode(new Node("Value 3B", m)));

    JTree tree = new JTree(root);
    RendererDispatcher rendererDispatcher = new RendererDispatcher(
        new JComboBox<String>());
    RendererDispatcher editorDispatcher = new RendererDispatcher(
        new JComboBox<String>());
    tree.setCellRenderer(rendererDispatcher);
    tree.setCellEditor(editorDispatcher);
    tree.setEditable(true);

    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new JScrollPane(tree));
    f.setSize(320, 240);
    f.setVisible(true);
  }
}

class Node {
  String name;
  String[] Values;
  int myIndex;

  public Node(String name, String... Values) {
    this.name = name;
    this.Values = Values;
  }

  public String toString() {
    return name;
  }

  public int getMyIndex() {
    return myIndex;
  }

  public void setIndex(int selectedValueIndex) {
    this.myIndex = selectedValueIndex;
  }

  public String[] getValues() {
    return Values;
  }
}

class RendererDispatcher extends DefaultCellEditor implements TreeCellRenderer {
  JPanel panel = new JPanel();
  JLabel ValueName = new JLabel();
  JComboBox<String> comboBox;
  Node node;
  public RendererDispatcher(JComboBox<String> comboBox) {
    super(comboBox);
    this.comboBox = comboBox;
    panel.setOpaque(false);
    panel.add(ValueName);
    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(ValueName.getText(), node.getValues());
    n.setIndex(m.getIndexOf(o));
    return n;
  }

  @Override
  public boolean isCellEditable(final EventObject event) {
    Object source = event.getSource();
    if (!(source instanceof JTree) || !(event instanceof MouseEvent)) {
      return false;
    }
    JTree tree = (JTree) source;
    MouseEvent mouseEvent = (MouseEvent) event;
    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())) {
      Point pt = SwingUtilities
          .convertPoint(tree, mouseEvent.getPoint(), panel);
      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;
    }
    ValueName.setText(node.toString());
    DefaultComboBoxModel<String> model = (DefaultComboBoxModel<String>) comboBox
        .getModel();
    model.removeAllElements();
    if (node.getValues().length > 0) {
      panel.add(comboBox);
      for (String s : node.getValues()) {
        model.addElement(s);
      }
      comboBox.setSelectedIndex(node.getMyIndex());
    } else {
      panel.remove(comboBox);
    }
  }
}