同时展开和折叠具有相同结构的两棵树

时间:2014-07-07 06:29:09

标签: java swing action jtree defaulttreemodel

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

enter image description here

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

我是否可以在每个DynamicTree对象中仅使用一个Jtree对象来实现此功能? (请参阅示例以查看这些对象是什么)有没有办法让Jtree只存储一个包含来自每个树的相应节点的数据的对象,但是要在不同的树上显示这些数据?

目前,我正在使用两个Jtree,可以通过将两个父项和两个子项作为add函数的输入来添加节点,并将相应的子项添加到相应的父项。
但是,在remove / expand / collapse函数中,我需要从两个树中删除/展开/折叠两个相应的节点。我该怎么做?

我是java swing的新手,但不是java编程。所以请说明需要了解Jswing的部分。

提前致谢。

1 个答案:

答案 0 :(得分:2)

所以,诀窍是使用单个TreeModel,链接树SelectionModel和两个自定义TreeCellRenderer并使用TreeExpansionListener能够确定哪个树展开/折叠并镜像结果。

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

扩展/崩溃有点困难,因为这需要通过自定义TreeExpansionListener来处理,它会检测是谁触发了事件,然后通知相反的树。

接下来,我使用一个普通的"数据对象" with,它包含有关应该由树显示的数据的基本信息...

最后,我使用两个不同的TreeCellRenderer来呈现由TreeModel

维护的数据的不同方面

Tree

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