Java tutorial
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; 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); } } }