【问题标题】:JTree shows same node as child nodeJTree 显示与子节点相同的节点
【发布时间】:2013-02-11 15:31:29
【问题描述】:

我正在为我的 JTree 使用自定义 TreeModel。我有一个根节点,只有 1 个子节点是通过数据库查询检索到的。我能够用所需的输出填充树。

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

}

【问题讨论】:

  • 你可以只发布相关的行吗?
  • 你真的认为我会读完这一切???
  • 并删除自解释方法名称中的 cmets
  • 只有几个 cmets:a) 为所有侦听器拥有一个实例变量(又名:静态字段)是 evil,它与实例的列表完全相同 b) 有周围有几个模型(一个在树中,一个单独) c)永远不会代表模型触发任何事件,这是它自己的责任 d)如果您使用 DefaultMutableTreeNodes 则不需要自定义模型(这就是 DefaultTreeModel 的用途)e ) 如果你坚持自己滚动:永远不要实现 add/removeListener 什么都不做——几乎所有的不当行为都与不正确的通知有关。空间不足 - 祝你好运:-)
  • 更多关于通常的EventListenerList实现here

标签: java swing jdbc jtree treenode


【解决方案1】:

您对 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,它将为您处理所有事情,避免您必须重新实现它,这意味着它所暗示的所有“风险”。

【讨论】:

  • 谢谢纪尧姆!!!!就像您建议的那样,我使用了 DefaultTreeModel 并解决了我的问题。我还只创建了一个 TreePanel 实例并将其用于更新树!感谢您的耐心和客气话。
猜你喜欢
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多