将监听器附加到JTree

时间:2014-05-28 23:52:33

标签: java swing jcombobox jtree

我之前问过这个问题:JTree selection issue

https://stackoverflow.com/users/177145/aterai使用以下代码回答:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;

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);
        RendererDispatcher rendererDispatcher = new RendererDispatcher(
                new JComboBox());
        RendererDispatcher editorDispatcher = new RendererDispatcher(
                new JComboBox());
        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);
    }
}

class Node {
    private final String name;
    private final String[] plugins;
    private int selectedPluginIndex;

    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;
    }
}

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

    public RendererDispatcher(JComboBox 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 m = (DefaultComboBoxModel) comboBox
                .getModel();
        Node n = new Node(pluginName.getText(), node.getPlugins());
        n.setSelectedPluginIndex(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;
        }
        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 model = (DefaultComboBoxModel) comboBox
                .getModel();
        model.removeAllElements();
        if (node.getPlugins().length > 0) {
            panel.add(comboBox);
            for (String s : node.getPlugins()) {
                model.addElement(s);
            }
            comboBox.setSelectedIndex(node.getSelectedPluginIndex());
        } else {
            panel.remove(comboBox);
        }
    }
}

我的下一个问题是,我在哪里放置听众,以便我知道哪个JComboBox已经改变了哪个插件?我认为它会是TreeSelectionListener,但是当我更改JComboBox中的所选项时,似乎无法触发。

1 个答案:

答案 0 :(得分:2)

如何使用TreeModelListener

tree.getModel().addTreeModelListener(new TreeModelListener() {
  @Override public void treeNodesChanged(TreeModelEvent e) {
    Object[] children = e.getChildren();
    if (children != null && children.length == 1
        && children[0] instanceof DefaultMutableTreeNode) {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) children[0];
      Object userObject = node.getUserObject();
      if (userObject instanceof Node) {
        Node uo = (Node) userObject;
        System.out.format(
            "%s %s%n", uo, uo.getPlugins()[uo.getSelectedPluginIndex()]);
      }
    }
  }
  @Override public void treeNodesInserted(TreeModelEvent e)  {}
  @Override public void treeNodesRemoved(TreeModelEvent e)   {}
  @Override public void treeStructureChanged(TreeModelEvent e) {}
});