2013-02-26 75 views
1

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

但是,当我点击子节点时,它将递归地显示相同的子节点,并且它不断添加具有相同输出的子节点。我试图使用静态节点,即我创建了一个根节点,然后向它添加了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) { 
    } 

} 
+2

你能发表只有相关的行吗? – Maroun 2013-02-26 08:48:31

+0

你真的认为我会读这一切? – Mordechai 2013-02-26 09:04:56

+0

,并删除自解释方法名称 – 2013-02-26 09:20:05

回答

2

你实现TreeModel的是笨拙的,是你的问题的原因:

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

private static DefaultMutableTreeNode rootPerson; 

- >坏,坏,坏,...真正的坏。其实完全没有必要做出这些声明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,它将为您处理所有事情,并避免您必须重新实施此操作,并具备所有“隐含的风险”。

+0

感谢Guillaume !!!!就像你建议的那样,我使用了DefaultTreeModel,它解决了我的问题。我也创建了我的TreePanel的一个实例并用它来更新树!感谢您的耐心和善意的话语。 – user547453 2013-02-26 19:04:27