After reading more on Java GUIs, I thought I'd adapt a BST to a GUI form. The idea is pretty basic: Insert a node and see as the tree gets painted every time you click the insert button.
However, no tree is being painted in my program, and I'm not getting any error messages.
My BinarySearchTree Class
public class BinarySearchTree {
class Node {
int key;
Node left;
Node right;
public Node(int item) {
key = item;
left = right = null;
}
}
int height;
Node root;
BinarySearchTree(){
root = null;
}
Node insert(int key) {
root = recursion(root, key);
return root;
}
Node recursion(Node root, int key) {
if(root == null) {
root = new Node(key);
return root;
}
if(key < root.key) {
root.left = recursion(root.left, key);
} else if (key > root.key) {
root.right = recursion(root.right, key);
}
return root;
}
private void height(Node key, int depth) {
if (key != null) {
height(key.left, depth + 1);
height = depth;
height(key.right, depth + 1);
}
}
public int getHeight() {
height(root, 1);
return height;
}
public JPanel getGraph() {
return new BSTGraph(this);
}
public void makeEmpty() {
root = null;
}
public boolean isEmpty() {
if(root==null)
return true;
else
return false;
}
}
My BSTGraph Class
public class BSTGraph extends JPanel{
private BinarySearchTree bst;
private HashMap nodeMap = null;
private HashMap subtreeSizes = null;
private boolean dirty = true;
private int parentToChild = 20, childToChild = 30;
private Dimension empty = new Dimension(0,0);
private FontMetrics fm = null;
public BSTGraph(BinarySearchTree bst)
{
this.bst = bst;
this.setBackground(Color.WHITE);
nodeMap = new HashMap();
subtreeSizes = new HashMap();
dirty = true;
repaint();
}
private void getPositions()
{
nodeMap.clear();
subtreeSizes.clear();
BinarySearchTree.Node root = this.bst.root;
if (bst.root != null)
{
getChildTreeSize(bst.root);
getPosition(root, Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
}
}
private void getPosition(BinarySearchTree.Node n, int left, int right, int top)
{
if (n == null)
return;
Dimension ld = (Dimension) subtreeSizes.get(n.left);
if (ld == null)
ld = empty;
Dimension rd = (Dimension) subtreeSizes.get(n.right);
if (rd == null)
rd = empty;
int center = 0;
if (right != Integer.MAX_VALUE)
center = right - rd.width - childToChild/2;
else if (left != Integer.MAX_VALUE)
center = left + ld.width + childToChild/2;
int width = fm.stringWidth(n.key+"");
nodeMap.put(n,new Rectangle(center - width/2 - 3, top, width + 6, fm.getHeight()));
getPosition(n.left, Integer.MAX_VALUE, center - childToChild/2, top + fm.getHeight() + parentToChild);
getPosition(n.right, center + childToChild/2, Integer.MAX_VALUE, top + fm.getHeight() + parentToChild);
}
private Dimension getChildTreeSize(BinarySearchTree.Node n)
{
if (n == null)
return new Dimension(0,0);
Dimension ld = getChildTreeSize(n.left);
Dimension rd = getChildTreeSize(n.right);
int h = fm.getHeight() + parentToChild + Math.max(ld.height, rd.height);
int w = ld.width + childToChild + rd.width;
Dimension d = new Dimension(w, h);
subtreeSizes.put(n, d);
return d;
}
private void graphTree(Graphics2D g, BinarySearchTree.Node n, int x, int y, int yOffSet)
{
if (n == null)
return;
Rectangle r = (Rectangle) nodeMap.get(n);
g.draw(r);
g.drawString(n.key+"", r.x + 3, r.y + yOffSet);
if (x != Integer.MAX_VALUE)
g.drawLine(x, y, (int)(r.x + r.width/2), r.y);
graphTree(g, n.left, (int)(r.x + r.width/2), r.y + r.height, yOffSet);
graphTree(g, n.right, (int)(r.x + r.width/2), r.y + r.height, yOffSet);
}
@Override
public void paint(Graphics g)
{
super.paint(g);
fm = g.getFontMetrics();
if (dirty)
{
getPositions();
dirty = false;
}
Graphics2D g2d = (Graphics2D) g;
g2d.translate(getWidth() / 2, parentToChild);
graphTree(g2d, this.bst.root, Integer.MAX_VALUE, Integer.MAX_VALUE,
fm.getLeading() + fm.getAscent());
fm = null;
}
}
Finally, a complement method in my GUI class which takes care of adding the "drawing" to a JInternalFrame element called graficoFrame
public void complement(){
Rectangle size = this.graficoFrame.getBounds();
this.graficoFrame = null;
this.graficoFrame = new JInternalFrame("Representación gráfica", true);
this.graficoFrame.setBounds(size);
this.graficoFrame.setEnabled(false);
this.repaintTree();
}
private void repaintTree() {
Rectangle size = this.graficoFrame.getBounds();
this.graficoFrame = null;
this.graficoFrame = new JInternalFrame("Representación gráfica", true);
this.graficoFrame.setBounds(size);
this.graficoFrame.setEnabled(false);
this.graficoFrame.add(bst.getGraph(), BorderLayout.CENTER);
this.graficoFrame.setVisible(true);
}
I've confirmed that the nodes are being correctly added and stored, however, the drawing never shows up, the JInternalFrame is still empty. Any visible reason why? based on this code
EDIT: I'm noticing it's not even creating the drawing, it's not giving it a title