I have already searched for answers. Some topics that pointed me in the right direction are:

How to draw a tree representing a graph of connected nodes? http://www.daniweb.com/software-development/java/threads/151175/drawing-tree-with-jframe

Anyway, here is the problem. I need to be able to draw a tree into a JFrame using no third party stuff; just methods available in swing. The code I have is below: the Tree class I didn't include, but it takes a text file and parses it into the tree structure. I'm running into two problems: First, I can't get the value for the node to show up in the oval. The value is stored as a string and should get passed through the Node. Second, the lines are not showing up, even though I overwrote paintComponent. Can someone help?

The NodeLabel:

public class NodeLabel extends JLabel{

public Node node;
public Point topConnection;
public Point bottomConnection;

public NodeLabel(Node _node){
    super(_node.value);
    node = _node;

    this.setText(node.value);
    this.add(new JLabel(node.value));
    topConnection = new Point(this.getWidth()/2, 0);
    bottomConnection = new Point(this.getWidth()/2, this.getHeight());
}


@Override
public void paintComponent(Graphics g){
    g.drawOval(5,  5,  25, 15);
}

The DrawTree Class:

private ArrayList<NodeLabel> nodes;
private Tree tree;
private NodeLabel root;
private int currentX;
private int currentY;

public DrawStuff(Tree _tree){
    tree = _tree;
    currentX = 40;
    currentY = 0;
    this.setLayout(null);
    this.setMinimumSize(new Dimension(300, 300));

    root = new NodeLabel(tree.root);
    root.setHorizontalAlignment(SwingConstants.CENTER);
    this.add(root);
    root.setBounds(currentX, currentY, currentX + 20, currentY + 25);
//      root.setLocation(currentX, currentY);



    currentX = currentX - 20;
    currentY = currentY + 30;

    for(Node node : tree.root.children){
        NodeLabel temp = new NodeLabel(node);
        this.add(temp);
        temp.setBounds(currentX, currentY, currentX +20, currentY + 25);
        this.add(drawEdge(this.getGraphics(), root, temp));

        temp.setLocation(currentX, currentY);
        currentX += 40;


        System.out.println("child added");
    }

}

private JPanel drawEdge(Graphics g, NodeLabel parent, NodeLabel child){     
    final Point p1 = parent.bottomConnection;
    final Point p2 = child.topConnection;

    JPanel line = new JPanel(){
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            g.drawLine(p1.x, p1.y, p2.x, p2.y);
        }
    };

    return line;
}

public static void main(String[] args) throws Exception{
    Tree tree = new Tree(args[0]);
    System.out.println(tree.toString());
    DrawStuff dTree = new DrawStuff(tree);
    dTree.setVisible(true);
}

The Tree Class: The tree takes a well-formed file (almost xml) and stores it in the data structure. Tags are formed like so: , with nested tags showing the hierarchy. IE:

public class Tree {

Node root;

/**
 * Tree constructor method
 * Takes the file and constructs a tree based on the contents
 * @param filename the name(or path) of the file to extract information from
 */
//Take the file and create all the nodes
public Tree(String filename) throws Exception{
    File file = new File(filename);
    Scanner s = new Scanner(file);

    Node current = new Node("x");
    if(s.hasNext()){
        s.next();
        String temp = s.next();
        String value = temp.substring(0, temp.length()-1);
        root = new Node(value);
        current = root;
    }
    while(s.hasNext()){
        String temp = s.next();
        if(temp.charAt(1) != '/'){ //then it is an open Tag.
            temp = s.next(); //this is our value + ">"
            String value = temp.substring(0, temp.length()-1);
            //create a new node with the value that's the child of our current node
            Node tempNode = current.addChild(value
                    );
            //current = the node we just created
            current = tempNode;     
        } else{
            if (current.parent!= null){
            current = current.parent;
            }
        }
    }
}

public String toString(){
    return root.toString();

}


public class Node{

    Node parent;
    ArrayList<Node> children;
    String value;

    public Node(String value){
        children = new ArrayList<Node>();
        this.value = value;
    }

    public Node(String value, Node parent){
        this.parent = parent;
        children = new ArrayList<Node>();
        this.value = value;
    }

    public Node addChild(String value){
        Node temp = new Node(value, this);
        this.children.add(temp);
        return temp;
    }

    public String toString(){
        String result = "";
        result += this.value + "\n"; 

        for(Node child:children){
            result += "    " + child.toString();
        }
        return result;
    }

}

}

有帮助吗?

解决方案

There are a number of serious issues that I can see. To start with, don't use multiple components to render distinct elements in this way. Instead, create a single custom component which has the capacity to render the whole content. This overcomes issues of coordinate context, which you don't seem to understand...

Start by removing the extends JLabel from the NodeLabel class, this class should simply be drawable in some way, so that you can pass the Graphics context to it and it will paint itself.

Create a TreePanel which extends from something like JPanel. This will act as the primary container for your tree. Provide a means by which you can set the tree reference. Override the component's paintComponent method and render the nodes to it, drawing the lines between them as you see fit...

Take a closer look at Performing Custom Painting and 2D Graphics for more details

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top