import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class TreeDemo extends JFrame {
public TreeDemo() {
super("TreeDemo");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(400, 400);
setLocationRelativeTo(null);
Tree tree = createDemoTree();
Node root = tree.getRoot();
root.moveTo(getSize().width / 2 - root.getBounds().width / 2, 20);
root.balanceX();
root.balanceY();
add(new TreeComponent(tree));
}
public static void main(final String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TreeDemo().setVisible(true);
}
});
}
private Tree createDemoTree() {
Node root = new Node(new Person("Peter"));
Node n2 = new Node(new Person("Andrew"));
Node n3 = new Node(new Person("Paul"));
Node n5 = new Node(new Person("Jane"));
Node n8 = new Node(new Person("Bert"));
Node n9 = new Node(new Person("Big Blue"));
n9.setBounds(new Rectangle(0, 0, 100, 100));
Node n10 = new Node(new Person("Benny"));
root.addChild(n3);
root.addChild(n9);
n3.addChild(n2);
n3.addChild(n5);
n9.addChild(n8);
n9.addChild(n10);
return new Tree(root);
}
}
class TreeComponent extends JPanel {
private Tree tree;
public TreeComponent(final Tree tree) {
this.tree = tree;
}
@Override
public void paintComponent(final Graphics g) {
drawTree(g, tree.getRoot());
}
private void drawTree(final Graphics g, final Node node) {
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawNode(g, node);
int numberOfChildren = node.numberOfChildren();
for (int i = 0; i < numberOfChildren; i++) {
drawTree(g, node.childNr(i));
}
}
private void drawNode(final Graphics g, final Node node) {
g.setColor(Color.BLACK);
g.drawRect(node.getBounds().x, node.getBounds().y,
node.getBounds().width, node.getBounds().height);
FontMetrics fm = getFontMetrics(getFont());
int i = fm.stringWidth(node.getElement().toString());
g.drawString(node.getElement().toString(), (node.getBounds().x
+ node.getBounds().width / 2) - (i / 2), node.getBounds().y
+ node.getBounds().height / 2);
g.setColor(Color.BLUE);
for (int j = 0; j < node.numberOfChildren(); j++) {
Node child = node.childNr(j);
g.drawLine(node.getBounds().x
+ node.getBounds().width / 2, node.getBounds().y
+ node.getBounds().height,
child.getBounds().x
+ child.getBounds().width / 2, child.getBounds().y);
}
}
}
class Node{
private Object data;
private List<Node> children;
private Rectangle bounds;
public Node(final Object o) {
data = o;
children = new ArrayList();
bounds = new Rectangle(0, 0, 50, 50);
}
public void addChild(final Node child) {
children.add(child);
}
public Object getElement() {
return data;
}
//
public Rectangle getBounds() {
return bounds;
}
public void setBounds(final Rectangle bounds) {
this.bounds = bounds;
}
public Node childNr(final int nr) {
return children.get(nr);
}
public int numberOfChildren() {
return children.size();
}
private int childrenWidth() {
int width = 0;
for (int i = 0; i < numberOfChildren(); i++) {
width += childNr(i).maxWidth();
if (i != numberOfChildren() - 1) {
width += 10;
}
}
return width;
}
private int maxWidth() {
int cWidth = childrenWidth();
if (cWidth > getBounds().width) {
return cWidth;
} else {
return getBounds().width;
}
}
public void balanceX() {
if (numberOfChildren() > 0) {
int cWidth = childrenWidth();
int middleX = getBounds().x + getBounds().width / 2;
int startX = middleX - cWidth / 2;
for (int i = 0; i < numberOfChildren(); i++) {
Node child = childNr(i);
int maxWidth = child.maxWidth();
int newX = (startX + maxWidth / 2) - child.getBounds().width / 2;
child.moveTo(newX, child.getBounds().y);
child.balanceX();
startX = startX + maxWidth + 10;
}
}
}
private void balanceY(final int height) {
int childHeight = 0;
int newY = getBounds().y + height + 20;
for (int i = 0; i < numberOfChildren(); i++) {
Node child = childNr(i);
if (child.getBounds().height > childHeight) {
childHeight = child.getBounds().height;
}
}
for (int i = 0; i < numberOfChildren(); i++) {
Node child = childNr(i);
child.moveTo(child.getBounds().x, newY);
child.balanceY(childHeight);
}
}
public void balanceY() {
balanceY(getBounds().height);
}
public void moveTo(final int newX, final int newY) {
getBounds().x = newX;
getBounds().y = newY;
}
}
class Tree {
private Node root;
public Tree(final Node root) {
this.root = root;
}
public Node getRoot() {
return root;
}
}
class Person{
private final String name;
public Person(final String name){
this.name = name;
}
@Override
public String toString(){
return name;
}
}