简体   繁体   中英

Java - Paint tree nodes onto JPanel

I'm trying to paint all nodes of a tree onto a JPanel recursively.

It should look like this:

在此处输入图片说明

Where, B , C , D , are children of A .

And, E , F are children of B

The output of parent child relationship is accurate:

PARENT: A | x,y: 180, 100...
 CHILD: B | x,y: 205, 150
PARENT: B | x,y: 205, 150...
 CHILD: E | x,y: 230, 200
PARENT: B | x,y: 205, 150...
 CHILD: F | x,y: 230, 200
end
PARENT: A | x,y: 180, 100...
 CHILD: C | x,y: 205, 150
PARENT: A | x,y: 180, 100...
 CHILD: D | x,y: 205, 150

But the x, y coordinates are not... Each child's x location overlaps the other child's... so it only shows 1 child node per parent:

在此处输入图片说明

I think what I have to do is find a way to increment y once per new row of children... and increment x for each child of a parent so they lay nicely on a single row... But the nodes' coordinates are resetting.

Any thoughts?

Code:

public void paintComponent(Graphics g) {
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, width, height);
    g.setColor(Color.CYAN);
    g.fillRect(rootNode.getX(), rootNode.getY(), rootNode.getWidth(), rootNode.getHeight());
    paintComponent(g, rootNode);

}

public void paintComponent(Graphics g, Nodes parentNode) {  
    //keep generating new nodePrintList to load with new Children
    ArrayList<Nodes> nodePrintList = new ArrayList<Nodes>();    

    //base case: end of nodeList
    if (nodeList.indexOf(parentNode)==nodeList.size()-1) {
        System.out.println("\nend");
    }
    else {  
    //traverse nodeList recursively 
        nodePrintList = getChildren(parentNode);    
        //loop through and print all children of node n
        System.out.println();

        for (Nodes child : nodePrintList) {             
            g.setColor(Color.GREEN);
            child.setX(parentNode.getX()+25);
            child.setY(parentNode.getY()+50);
            g.fillRect(child.getX(), child.getY(), child.getWidth(), child.getHeight());
            System.out.print("PARENT: " + parentNode.getValue() + " | x,y: " + parentNode.getX() + ", " + parentNode.getY() + "...\n CHILD: " + child.getValue() + " | x,y: " + child.getX() + ", " + child.getY());    
            paintComponent(g, child);
        }           
    }
}

getChildren() method to return list of children per parent:

//need to pass a new index to getChildren once current node has no more children
public ArrayList<Nodes> getChildren (Nodes n) {
    ArrayList<Nodes> childrenList;
    childrenList = new ArrayList<Nodes>();  
    int index = nodeList.indexOf(n);
    int col = 0;

    while (col < size) {
        if (adjMatrix[index][col] == 1) {
            childrenList.add(nodeList.get(col));
        }
        col++;
    }
    return childrenList;
}

The main problem seems to be in the for loop in your paintComponent method. Here, you are using the same x coordinate for each children. You could fix it like this:

int x = parentNode.getX()+25; // x position of first child
for (Nodes child : nodePrintList) {
    child.setX(x);
    child.setY(parentNode.getY()+50); // y position is same for each child
    // [...] fill rect, print, recursive call, etc.
    x -= 50; // in each iteration, move nodes further to the left
}

However, this is just one problem. Another issue is, that for properly laying out the nodes, you have to take into account the total width of each branch. One way to fix this could be to return the total width of each branch, have paintComponent(g, nodes) return x , and use this (plus some offset) for the next child. The above code could then look somewhat like this:

int x = parentNode.getX()+25; // x position of first child
for (Nodes child : nodePrintList) {
    child.setX(x);
    child.setY(parentNode.getY()+50); // y position is same for each child
    // [...] fill rect, print, etc.
    x = paintComponent(g, child) - 50; // next x is left of the total width of the child
}
return x; // return x (change methods signature accordingly)

This probably still needs some tinkering, but it should give you the idea.

The problem is right here:

for (Nodes child : nodePrintList) {             
    //...
    child.setX(parentNode.getX()+25);
    //...
}

Your program code is always setting the child node's position to a fixed x and y distance from the parent, regardless of which node it is.

One solution to this:

for (int idx = 0; idx < nodePrintList.size(); idx++) {
    Nodes node = nodePrintList.get(idx);             
    //...
    child.setX(parentNode.getX()+ 25 * ((float)(nodePrintList.size()-1)/2 - idx);
    //...
}

While my math may be a little off, this should equally space all the child nodes directly under the parent, each 25 units away from the next.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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