我想修改此链接中给出的Swing示例中的标准JTree-> Dynamic Tree Example
该应用程序的屏幕截图如下:
DynamicTreeDemo



我想使用这种结构来维护两棵树,它们都具有完全相同的结构。
当通过鼠标单击折叠/展开任何一个时,我都应该能够同时折叠和展开!
同样,当用户从任一棵树中选择一个节点时,另一棵树中的相应节点也应突出显示。
一棵树可能包含文件/文件夹作为节点,而另一棵树可能具有创建时间作为节点。

我可以在每个DynamicTree对象中仅使用一个Jtree对象来使其工作吗? (请参阅示例以查看这些对象是什么。)是否有任何方法可以使Jtree仅存储一个包含来自每棵树的相应节点的数据的对象,而是在单独的树上显示这些数据?

当前,我正在使用两个Jtree,可以通过将两个父对象和两个孩子作为add函数的输入并将相应的孩子添加到相应的父对象来添加节点。
但是,在删除/扩展/折叠功能中,我需要从两棵树中删除/扩展/折叠两个对应的节点。我该怎么做呢?

我是java swing的新手,但不是Java编程的人。因此,请阐明需要了解Jswing的部分。

提前致谢。

最佳答案

因此,诀窍是使用单个TreeModel,将树的SelectionModel和两个自定义的TreeCellRenderer链接起来,并使用能够确定哪棵树展开/折叠并镜像结果的TreeExpansionListener

基本上,每棵树共享相同的TreeModelSelectionModel,这使生活变得更加简单,因为它们都将响应对两个模型所做的更改。

扩展/折叠要困难一些,因为这需要通过自定义TreeExpansionListener进行处理,该自定义TreeCellRenderer可以检测谁触发了事件,然后将更改通知给相反的树。

接下来,我使用一个通用的“数据对象”,其中包含有关应该由树的树显示的数据的基本信息。

最后,我使用两个不同的TreeModel来呈现维护的数据的不同方面



import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

public class DynamicTreeDemo extends JPanel implements ActionListener {

    protected static final SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss");

    private int newNodeSuffix = 1;
    private static String ADD_COMMAND = "add";
    private static String REMOVE_COMMAND = "remove";
    private static String CLEAR_COMMAND = "clear";

    private DefaultMutableTreeNode rootNode;
    private final DefaultTreeModel treeModel;

    private JTree left;
    private JTree right;

    public DynamicTreeDemo() {
        super(new BorderLayout());

        rootNode = new DefaultMutableTreeNode("Root Node");
        treeModel = new DefaultTreeModel(rootNode);

        left = new JTree(treeModel);
        left.setCellRenderer(new LeftTreeCellRenderer());
        right = new JTree(treeModel);
        right.setCellRenderer(new RightTreeCellRenderer());

        MyExpansionListener expansionListener = new MyExpansionListener(left, right);

        left.addTreeExpansionListener(expansionListener);
        right.addTreeExpansionListener(expansionListener);

        right.setSelectionModel(left.getSelectionModel());

        populateModel();

        JButton addButton = new JButton("Add");
        addButton.setActionCommand(ADD_COMMAND);
        addButton.addActionListener(this);

        JButton removeButton = new JButton("Remove");
        removeButton.setActionCommand(REMOVE_COMMAND);
        removeButton.addActionListener(this);

        JButton clearButton = new JButton("Clear");
        clearButton.setActionCommand(CLEAR_COMMAND);
        clearButton.addActionListener(this);

        JPanel panel = new JPanel(new GridLayout(1, 2));
        panel.add(new JScrollPane(left));
        panel.add(new JScrollPane(right));
        add(panel, BorderLayout.CENTER);

        JPanel buttons = new JPanel(new GridLayout(0, 3));
        buttons.add(addButton);
        buttons.add(removeButton);
        buttons.add(clearButton);
        add(buttons, BorderLayout.SOUTH);
    }

    protected TreeData createNodeData() {
        return new TreeData("New Node " + newNodeSuffix++, SDF.format(new Date()));
    }

    public void populateModel() {
        String p1Name = "Parent 1";
        String p2Name = "Parent 2";

        DefaultMutableTreeNode p1, p2;

        p1 = addObject(null, p1Name);
        p2 = addObject(null, p2Name);

        addObject(p1, createNodeData());
        addObject(p1, createNodeData());

        addObject(p2, createNodeData());
        addObject(p2, createNodeData());

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();

        if (ADD_COMMAND.equals(command)) {
            // Add button clicked
            addObject(createNodeData());
        } else if (REMOVE_COMMAND.equals(command)) {
            // Remove button clicked
            removeCurrentNode();
        } else if (CLEAR_COMMAND.equals(command)) {
            // Clear button clicked.
            clear();
        }
    }

    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        // Create and set up the window.
        JFrame frame = new JFrame("DynamicTreeDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create and set up the content pane.
        DynamicTreeDemo newContentPane = new DynamicTreeDemo();
        newContentPane.setOpaque(true); // content panes must be opaque
        frame.setContentPane(newContentPane);

        // Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    /**
     * Remove all nodes except the root node.
     */
    public void clear() {
        rootNode.removeAllChildren();
        treeModel.reload();
    }

    /**
     * Add child to the currently selected node.
     */
    public DefaultMutableTreeNode addObject(Object child) {
        DefaultMutableTreeNode parentNode = null;
        TreePath parentPath = left.getSelectionPath();

        if (parentPath == null) {
            parentNode = rootNode;
        } else {
            parentNode = (DefaultMutableTreeNode) (parentPath.getLastPathComponent());
        }

        return addObject(parentNode, child, true);
    }

    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
            Object child) {
        return addObject(parent, child, false);
    }

    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
            Object child, boolean shouldBeVisible) {
        DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child);

        if (parent == null) {
            parent = rootNode;
        }

        // It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode
        treeModel.insertNodeInto(childNode, parent, parent.getChildCount());

        // Make sure the user can see the lovely new node.
        if (shouldBeVisible) {
            left.scrollPathToVisible(new TreePath(childNode.getPath()));
            right.scrollPathToVisible(new TreePath(childNode.getPath()));
        }
        return childNode;
    }

    /**
     * Remove the currently selected node.
     */
    public void removeCurrentNode() {
        TreePath currentSelection = left.getSelectionPath();
        if (currentSelection != null) {
            DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection
                    .getLastPathComponent());
            MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
            if (parent != null) {
                treeModel.removeNodeFromParent(currentNode);
                return;
            }
        }

    }

    public class TreeData {

        private String left;
        private String right;

        public TreeData(String left, String right) {
            this.left = left;
            this.right = right;
        }

        public String getLeft() {
            return left;
        }

        public String getRight() {
            return right;
        }

    }

    public class LeftTreeCellRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            if (value instanceof DefaultMutableTreeNode) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
                Object userData = node.getUserObject();
                if (userData instanceof TreeData) {
                    value = ((TreeData) userData).getLeft();
                }
            }
            return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
        }

    }

    public class RightTreeCellRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            if (value instanceof DefaultMutableTreeNode) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
                Object userData = node.getUserObject();
                if (userData instanceof TreeData) {
                    value = ((TreeData) userData).getRight();
                }
            }
            return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
        }

    }

    public class MyExpansionListener implements TreeExpansionListener {

        private JTree left;
        private JTree right;

        public MyExpansionListener(JTree left, JTree right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public void treeExpanded(TreeExpansionEvent event) {
            TreePath path = event.getPath();
            if (event.getSource() == left) {
                right.expandPath(path);
            } else {
                left.expandPath(path);
            }
        }

        @Override
        public void treeCollapsed(TreeExpansionEvent event) {
            TreePath path = event.getPath();
            if (event.getSource() == left) {
                right.collapsePath(path);
            } else {
                left.collapsePath(path);
            }
        }

    }
}


有关更多详细信息,请参见How to Use Trees

10-01 12:28