简体   繁体   English

来自ArrayList的JTree不显示节点

[英]JTree from ArrayList not displaying nodes

I have a custom data structure that is basically just a named ArrayList of ArrayLists. 我有一个自定义数据结构,它基本上只是一个ArrayLists的命名ArrayList。 Similar to XML. 与XML类似。

(have stripped out un-nesecary code) (已删除非密码)

    public class Element extends ArrayList<Element> {
        private String name;


        public Element(String n){

            name = n;
        }

        @Override
        public String toString(){

            return name;
        }
    }

I am trying to display this in a JTree using a custom TreeModel class. 我正在尝试使用自定义TreeModel类在JTree中显示此内容。 However the JTree does not display properley. 但是,JTree不会正确显示。 Only one node is displayed at the end of a branch, when the child node is selected it shows the last child node but when un-selected it shows the first child node, but still at the end of the branch. 在分支的末尾仅显示一个节点,当选择子节点时,它显示最后一个子节点,但是当未选中时,它显示第一个子节点,但仍在分支的末尾。

捕获

From extensive de-bugging I can see it reads the all the child nodes and count correctly it just doens't display them. 通过广泛的调试,我可以看到它读取了所有子节点并正确计数,只是不显示它们。 I suspect they are all being displayed on top of each other but don't know why or what to do about it. 我怀疑它们全都显示在彼此的顶部,但不知道为什么或怎么做。

Any thoughs appreciated. 任何赞赏。

public class TestModel implements TreeModel{

    Element data;

    TestModel(){      
        data = new Element("data");

        data.add(new Element("One"));
        data.add(new Element("Two"));
        data.add(new Element("Three"));
        data.add(new Element("Four"));
        data.add(new Element("Five"));
    }

    @Override
    public Object getRoot() {
        return data;
    }

    @Override
    public Object getChild(Object parent, int index) {

        if(parent instanceof Element){
            Element p = (Element)parent;
            Element child = p.get(index);

            return child;
        }

        return null;
    }

    @Override
    public int getChildCount(Object parent) {

        if(parent instanceof Element){
            Element e = (Element)parent;
            return e.size();
        }

        return 0;
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {

        if(parent instanceof Element){
            Element e = (Element)parent;

            return e.indexOf(child);
        }

        return -1;

    }

    @Override
    public boolean isLeaf(Object node) {
        //List<? super ArrayList> d = (List<? super ArrayList>) node;

        if(node instanceof Element){
            Element e = (Element)node;
            return e.isEmpty();
        }

        return true;
    }
}

The problem is the way in which you are using the Element class and extending it from ArrayList . 问题是您使用Element类并将其从ArrayList扩展的方式。 This comes down to how the hashcode is calculated from an ArrayList (or AbstractList to be more accurate. 这归结为如何从ArrayList (或AbstractList ,更准确地说)计算hashcode

The hashcode is calculted based on the elements in the ArrayList , which is 0 for all the child Element s, resulting in a hashcode of 1 for all of them, which is causing issues with the List look up and uniquely identifying the elements. hashcode是根据ArrayList的元素计算得出的,对于所有子Elementhashcode均为0 ,导致所有子Elementhashcode均为1 ,这会导致List查找和唯一标识元素的问题。

Personally, I would create a Node class which contained a List member and which provided additional functionality that could work with the TreeModel or just use TreeNode ... 我个人将创建一个Node类,其中包含一个List成员,并提供可以与TreeModel使用或仅使用TreeNode其他功能。

For example... 例如...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

public class TestTree {

    public static void main(String[] args) {
        new TestTree();
    }

    public TestTree() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JTree tree = new JTree(new TestModel());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(tree));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestModel implements TreeModel {

        Element data;

        TestModel() {
            data = new Element("data");

            data.add(new Element("One"));
            data.add(new Element("Two"));
            data.add(new Element("Three"));
            data.add(new Element("Four"));
            data.add(new Element("Five"));
        }

        @Override
        public Object getRoot() {
            return data;
        }

        @Override
        public Object getChild(Object parent, int index) {

            System.out.println("GetChild from " + parent + " @ " + index);

            if (parent instanceof Element) {
                Element p = (Element) parent;
                Object child = p.getChildAt(index);

                System.out.println("child = " + child);
                return child;
            }

            return null;
        }

        @Override
        public int getChildCount(Object parent) {

            if (parent instanceof Element) {
                Element e = (Element) parent;
                System.out.println("childCount = " + parent + "; " + e.getChildCount());
                return e.getChildCount();
            }

            return 0;
        }

        @Override
        public int getIndexOfChild(Object parent, Object child) {

            if (parent instanceof Element && child instanceof Element) {
                Element e = (Element) parent;

                System.out.println("indexOf " + child + " in " + parent + " is " + e.getIndex((Element)child));
                return e.getIndex((Element)child);
            }

            return -1;

        }

        @Override
        public boolean isLeaf(Object node) {
            //List<? super ArrayList> d = (List<? super ArrayList>) node;

            if (node instanceof Element) {
                Element e = (Element) node;
                System.out.println("isLeaf " + e + "; " + (e.getChildCount() == 0));
                return e.getChildCount() == 0;
            }

            return true;
        }

        @Override
        public void valueForPathChanged(TreePath path, Object newValue) {

        }

        @Override
        public void addTreeModelListener(TreeModelListener l) {

        }

        @Override
        public void removeTreeModelListener(TreeModelListener l) {

        }
    }

    public static class Element implements TreeNode {

        private List<Element> nodes;
        private Element parent;

        private String name;

        public Element(String n) {

            nodes = new ArrayList<>(25);
            name = n;
        }

        @Override
        public String toString() {

            return name;
        }

        protected void setParent(Element parent) {
            this.parent = parent;
        }

        public void add(Element node) {
            node.setParent(this);
            nodes.add(node);
        }

        public void remove(Element node) {
            node.setParent(null);
            nodes.remove(node);
        }

        @Override
        public TreeNode getChildAt(int childIndex) {
            return nodes.get(childIndex);
        }

        @Override
        public int getChildCount() {
            return nodes.size();
        }

        @Override
        public TreeNode getParent() {
            return parent;
        }

        @Override
        public int getIndex(TreeNode node) {
            return nodes.indexOf(node);
        }

        @Override
        public boolean getAllowsChildren() {
            return true;
        }

        @Override
        public boolean isLeaf() {
            return nodes.isEmpty();
        }

        @Override
        public Enumeration children() {
            return Collections.enumeration(nodes);
        }
    }
}

Or you could just use one of the pre-defined TreeNode classes, like DefaultMutableTreeNode 或者,您可以只使用一种预定义的TreeNode类,例如DefaultMutableTreeNode

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM