Question

My question is a little hard for me to word, but basically this is what I want to do: I have a homework assignment to draw a recursive tree with the user having the ability to choose the amount of nodes displayed. I have a draw method that draws a tree using recursion and I need the program to accept user input from a text field. I am new to recursion, but my roommate and I managed to draw something by using Graphics2D, but we can't begin to figure out how to allow a user to choose the amount of nodes. The skeleton for the input field is there, but it doesn't do anything since I have no ActionListener and don't exactly know what to put into ActionListener to allow the user to input a value. Any help would be greatly appreciated. Thanks!

import java.awt.*;
import javax.swing.*;

public class Tree extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel num; //tells user to enter number of nodes
    private JTextField in; //text field for user input

    public Tree() {
        num = new JLabel("Number of Branches: ");
        add(num);
        in = new JTextField(5);
        add(in);
    }

    private void draw(Graphics2D g, int n, int x, int y) {
        if (n == 0) {
            return;
        } else {
            int angle = 45;
            int length = 50;
            g.drawLine(x, y, x, y - length); // trunk
            g.setColor(Color.BLACK);
            g.rotate(Math.toRadians(-angle), x, y - length); // left
            // branch
            draw(g, n - 1, x, y - length);
            g.rotate(Math.toRadians(angle), x, y - length);
            g.rotate(Math.toRadians(angle), x, y - length); // right
            // branch
            draw(g, n - 1, x, y - length);
            g.rotate(Math.toRadians(-angle), x, y - length);
        }
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D gg = (Graphics2D) g;
        draw(gg, 3, getWidth() / 2, getHeight() / 2);
    }

    public static void main(String[] args) {
        Tree tree = new Tree();
        tree.setPreferredSize(new Dimension(500, 500));
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(tree);
        frame.setSize(500, 500);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
Was it helpful?

Solution

I would personally use the MVC(Model-View-Controller) model to organize my code keeping the display, processing, and communication between the two all separate. It's easier that way to keep track of what is happening. In your case, the tree object is the drawing and the labels and the buttons. But since you already wrote the code it would be easier to just adjust it.

To add an action listener you need to register the user input as an event and a button to 'capture it'. The event in this sense will be the user pressing the button. Thus, once the user enters the number of nodes and presses the button, the action listener responds to this event and executes the needed code(drawing the tree).

Here is how I would do it:

  • give a tree object a changeable node number.
  • create a class that implements actionListener.
  • create a button and assign to it an actionListener.
  • create a static reference to the drawn tree, change its node number once a button is clicked, and update it on the screen.

import java.awt.*;

import javax.swing.*;

public class Tree extends JPanel {

private static final long serialVersionUID = 1L;

// I made all components static since you only need one copy of each
private static JLabel num; //tells user to enter number of nodes
private static JTextField in; //text field for user input
private static JButton enter = new JButton("Enter");// create a button to capture event

private static Tree tempTree; 

private int nodeNumber;   // makes a tree's node number changeable

public Tree() {

    this.nodeNumber = 0;
    num = new JLabel("Number of Branches: ");
    add(num);
    in = new JTextField(5);
    add(in);
    add(enter);
    add(enter);
}



private void draw(Graphics2D g, int n, int x, int y) {
    if (n == 0) {
        return;
    } else {
        int angle = 45;
        int length = 50;
        g.drawLine(x, y, x, y - length); // trunk
        g.setColor(Color.BLACK);
        g.rotate(Math.toRadians(-angle), x, y - length); // left
        // branch
        draw(g, n - 1, x, y - length);
        g.rotate(Math.toRadians(angle), x, y - length);
        g.rotate(Math.toRadians(angle), x, y - length); // right
        // branch
        draw(g, n - 1, x, y - length);
        g.rotate(Math.toRadians(-angle), x, y - length);
    }
}

// I had to overload your draw method to one in which I can change the drawing multiple times later
private void draw(Graphics2D g, int x, int y)
{
        int n = this.nodeNumber;
       if (n == 0) {
           return;
       } else {
           int angle = 45;
           int length = 50;
           g.drawLine(x, y, x, y - length); // trunk
           g.setColor(Color.BLACK);
           g.rotate(Math.toRadians(-angle), x, y - length); // left
           // branch
           draw(g, n - 1, x, y - length);
           g.rotate(Math.toRadians(angle), x, y - length);
           g.rotate(Math.toRadians(angle), x, y - length); // right
           // branch
           draw(g, n - 1, x, y - length);
           g.rotate(Math.toRadians(-angle), x, y - length);
       }
}

//makes a tree's node number editable
public void setNodeNumber(int number)
{
    this.nodeNumber = number;
}

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D gg = (Graphics2D) g;

    //this version can change node number
    draw(gg,getWidth() / 2, getHeight() / 2);
}

public static void main(String[] args) {

    Tree tree = new Tree();
    tree.setPreferredSize(new Dimension(500, 500));
    JFrame frame = new JFrame("Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(tree);
    frame.setSize(500, 500);

    // stores the currently displayed tree for later changes
    Tree.tempTree = tree;
    Listener enterListener = new Listener();

    Tree.enter.setActionCommand("ENTER");
    Tree.enter.addActionListener(enterListener);


    frame.setLocationRelativeTo(null);
    frame.setVisible(true);


}

// refreshes tree
public static void refreshTree()
{



    int inputNumber;

    // checks if input is a number or not
    try
    {
        //gets input node number 
        inputNumber =  Integer.parseInt(Tree.in.getText());

        //sets node number 
        Tree.tempTree.setNodeNumber(inputNumber);
        // updates tree
        Tree.tempTree.updateUI();
    }
    catch(NumberFormatException e)
    {
        System.out.println(" Invalid node Number " + e);
    }



}

}

You will also need an action listener class:

import java.awt.event.ActionEvent; import java.awt.event.ActionListener;

public class Listener implements ActionListener{

@Override
public void actionPerformed(ActionEvent event) {
    String action = event.getActionCommand();
    if(action.equals("ENTER"))
    {

        Tree.refreshTree();
    }


}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top