JTree显示与子节点相同的节点

时间:2013-02-26 08:46:42

标签: java swing jdbc jtree treenode

我正在为我的JTree使用自定义TreeModel。我有一个根节点,只有一个子节点由数据库中的查询检索。我可以使用所需的输出填充树。

但是,当我单击子节点时,它会以递归方式显示相同的子节点,并且不断添加具有相同输出的子节点。我尝试使用静态节点,即我创建了一个根节点,然后添加了2个子节点,我观察到了相同的行为。

我的主要计划

import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;

public class RunApp {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ShowFrame f = new ShowFrame();

                f.setSize(600, 600);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setVisible(true);
            }
        });
    }
}

我的show_frame类

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;

public class ShowFrame extends JFrame {

    private JSplitPane splitPane;
    private FormPanel formPanel;
    private TreePanel treePanel;
    private JTabbedPane tabPane;
    private List<Objects> instanceDetails= new ArrayList<Objects>();

    public ShowFrame() {
        super("new frame");
        formPanel = new FormPanel();
        instanceDetails.add(new Objects(" "," "," "," "));
        treePanel = new TreePanel(instanceDetails);
        tabPane = new JTabbedPane();
        tabPane.add(treePanel);

        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, formPanel,
                tabPane);
        splitPane.setOneTouchExpandable(true);

        setMinimumSize(new Dimension(500, 500));
        add(splitPane, BorderLayout.CENTER);
    }
}

这是我创建TreePanel的地方

import java.util.List;

import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

public class TreePanel extends JPanel {

    private int count = 0;

    private JTree tree;
    private List<Objects> instanceDetails;
    private MyTreeModel gm;
    private DefaultMutableTreeNode root = new DefaultMutableTreeNode();

    private Controller c = new Controller();

    public TreePanel(List<Objects> instanceDetails) {
        this.instanceDetails = instanceDetails;
        tree = new JTree();

        if (instanceDetails.get(0).getObjectId() == " ") {
            tree.setModel(new MyTreeModel(root));

        } else {
            tree.setModel(new MyTreeModel(treeNodes(instanceDetails)));
        }

        gm = new MyTreeModel(root);
        gm.fireTreeStructureChanged(root);

        tree.getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);
        add(tree);


    }

    private DefaultMutableTreeNode treeNodes(List<Objects> instanceDetails) {
        for (Objects id : instanceDetails) {
            count++;

            DefaultMutableTreeNode objs = new DefaultMutableTreeNode(count + " : " + id.getType()
                    + " : " + id.getObjectId() + " : " + id.getStatus() + " : "
                    + id.getCondition());

            root.add(objs);
        }

        return root;
    }

}

我的树模型

import java.util.Vector;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;


public class MyTreeModel implements TreeModel {

    public static Vector<TreeModelListener> treeModelListeners =
        new Vector<TreeModelListener>();

    private static DefaultMutableTreeNode rootPerson;

     public MyTreeModel(DefaultMutableTreeNode nodes) {
        rootPerson = nodes;
    }

     //////////////// Fire events //////////////////////////////////////////////

    /**
     * The only event raised by this model is TreeStructureChanged with the
     * root as path, i.e. the whole tree has changed.
     */
    protected void fireTreeStructureChanged(DefaultMutableTreeNode rootPerson) {
        TreeModelEvent e = new TreeModelEvent(this, new Object[] {rootPerson});
        for (TreeModelListener tml : treeModelListeners) {
            tml.treeStructureChanged(e);
        }
    }


     //////////////// TreeModel interface implementation ///////////////////////

    /**
     * Adds a listener for the TreeModelEvent posted after the tree changes.
     */
    public void addTreeModelListener(TreeModelListener l) {
        treeModelListeners.addElement(l);    
       }

    /**
     * Returns the child of parent at index index in the parent's child array.
     */
    public Object getChild(Object parent, int index) {
        return rootPerson.getChildAt(index);
    }

    /**
     * Returns the number of children of parent.
     */
    public int getChildCount(Object parent) {
        return 1;
        //rootPerson.getLeafCount()

    }

    /**
     * Returns the index of child in parent.
     */
    public int getIndexOfChild(Object parent, Object child) {
        return rootPerson.getIndex((DefaultMutableTreeNode) child);
    }

    /**
     * Returns the root of the tree.
     */
    public Object getRoot() {
        return rootPerson;
    }

    /**
     * Returns true if node is a leaf.
     */
    public boolean isLeaf(Object node) {
        return rootPerson.isLeaf();
    }

    /**
     * Removes a listener previously added with addTreeModelListener().
     */
    public void removeTreeModelListener(TreeModelListener l) {
       //removeTreeModelListener(l);
    }

    /**
     * Messaged when the user has altered the value for the item
     * identified by path to newValue.  Not used by this model.
     */
    public void valueForPathChanged(TreePath path, Object newValue) {
    }

}

1 个答案:

答案 0 :(得分:2)

TreeModel的实现很笨拙,是导致问题的原因:

public static Vector<TreeModelListener> treeModelListeners =
    new Vector<TreeModelListener>();

private static DefaultMutableTreeNode rootPerson;

- &GT;坏,坏,坏,......真的很糟糕。绝对没有必要发表这些陈述static如果您碰巧创建了2个不同的实例,这将导致严重的问题

/**
 * Returns the child of parent at index index in the parent's child array.
 */
public Object getChild(Object parent, int index) {
    return rootPerson.getChildAt(index);
}

在这里,无论提供哪个parent,你总是会返回同一个孩子(因此这就是为什么你一遍又一遍地看到同一个孩子)。代码应为return (parent==rootPerson?rootPerson.getChildAt(index):null);

/**
 * Returns the number of children of parent.
 */
public int getChildCount(Object parent) {
    return 1;
    //rootPerson.getLeafCount()

}

与之前的评论相同,您不会查看parent是什么。代码应为return (parent==rootPerson?1:0);

/**
 * Returns the index of child in parent.
 */
public int getIndexOfChild(Object parent, Object child) {
    return rootPerson.getIndex((DefaultMutableTreeNode) child);
}

与之前的评论相同,您不会查看parent是什么。代码应为return (parent==rootPerson?rootPerson.getIndex((DefaultMutableTreeNode) child):-1);

/**
 * Returns true if node is a leaf.
 */
public boolean isLeaf(Object node) {
    return rootPerson.isLeaf();
}

同样,同样的错误,你不关心node

/**
 * Removes a listener previously added with addTreeModelListener().
 */
public void removeTreeModelListener(TreeModelListener l) {
   //removeTreeModelListener(l);
}

为什么不正确实现removeTreeModelListener? (根据@trashgod的建议,你总是可以使用默认的EventListenerList来完成你的大部分工作)

结论:TreeModel的实现充满了错误,这就是您遇到问题的原因。现在,既然你正在使用DefaultMutableTreeNode,我只能鼓励你也使用DefaultTreeModel来处理你的一切,避免你必须重新实现它,它意味着所有的“风险”