2013-02-26 72 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