Search code examples
javaswinglayoutpaintcomponent

Issue in understanding whats wrong with my code


I have been trying to fix this error but I cant seem to figure it out whats wrong. I want to write a program that prompts the user to enter the x- and y-positions of the center and a radius. When the user clicks a “Draw” button, draw a circle with that center and radius in a component.

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class CircleMakerVeiwer {

public static void main(String[] args) {
    // stuff that displays that will help display the circle
    JPanel panel = new JPanel();
    JPanel pane2 = new JPanel();
    JFrame frame = new JFrame();
    JButton button = new JButton("Draw Circle");

    // the obj that will be drawn
    CircleMaker circle = new CircleMaker();

    // panel is set to a flowLayout
    panel.setLayout(new FlowLayout());
    // panel's size is selected
    panel.setPreferredSize(new Dimension(800, 800));

    // now here's where the fun begins

    // labels
    JLabel x_cor = new JLabel("X Cordinate");
    JLabel y_cor = new JLabel("Y Cordinate");
    JLabel rad = new JLabel("Radius");

    // JTextFeilds
    JTextField x_input = new JTextField(3);
    JTextField y_input = new JTextField(3);
    // [in surfer dude voice] It's so RADDDD bROOOo
    JTextField rad_input = new JTextField(3);

    // all de panel adding
    panel.add(x_cor);
    panel.add(x_input);
    panel.add(y_cor);
    panel.add(y_input);
    panel.add(rad);
    panel.add(rad_input);


    // time for the action listener
    class DrawCircleListener implements ActionListener {

        public void actionPerformed(ActionEvent arg0) {
            int x, y, r;
            System.out.println("action preformed (sort of)");
            x = Integer.parseInt(x_input.getText());
            y = Integer.parseInt(y_input.getText());
            r = Integer.parseInt(rad_input.getText());

            circle.setCircle(r, x, y);

        }// end of actionPerformed

    }// end of DrawCircleListener
    DrawCircleListener listener = new DrawCircleListener();



    button.addActionListener(listener);
    panel.add(button);

    panel.add(circle);

    frame.setSize(800, 800);
    frame.setTitle("Circle Button");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(panel);

    frame.setVisible(true);

   }// end of main

}// end of CircleMakerVeiwer.java

I am going to be giving the CircleMaker object as well to see if anything just in case.

    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.geom.Ellipse2D;

    import javax.swing.JComponent;

    /*
     * This program will construct a circle it will also 
     * paint and set the parameters of the circle outside the constructor 
     */

public class CircleMaker extends JComponent {

private Ellipse2D.Double c;
    private int radius, x_cor, y_cor;

public CircleMaker() {
    c= new Ellipse2D.Double();
}

public void setCircle(int r, int x_cordinate, int y_cordinate) {
    //Graphics g;
    c = new Ellipse2D.Double(x_cordinate - r, y_cordinate - r, r * 2, r * 2);
    System.out.println("set circle was called");
    //repaint();
}

public void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.draw(c);

}


}

Solution

    1. You're adding CircleMaker to a JPanel which is using FlowLayout, which honors the preferredSize of the components, but CircleMaker's default preferredSize is 0x0, so the component is effectively invisible
    2. You don't call repaint when setCircle is called, so the component has no idea that it should be updated
    3. You're violating the paint method chain contract by not calling super.paintComponent before doing your custom painting

    Start by overriding the getPreferredSize method of CircleMaker...

    public static class CircleMaker extends JComponent {
        //...
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    

    This will provide some idea of how big you'd like you component to be normally to the layout managers

    Update the setCircle method to call repaint and add super.paintComponent to your paintComponent method

        public void setCircle(int r, int x_cordinate, int y_cordinate) {
            //Graphics g;
            c = new Ellipse2D.Double(x_cordinate - r, y_cordinate - r, r * 2, r * 2);
            System.out.println("set circle was called");
            repaint();
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.draw(c);
    
        }
    

    Finally, add the instance of CircleMaker to the CENTER position of the frame, which uses a BorderLayout by default...

        //panel.add(circle);
    
        frame.setTitle("Circle Button");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel, BorderLayout.NORTH);
        frame.add(circle);
    
        frame.pack();
        frame.setVisible(true);
    

    Oh, and get rid of panel.setPreferredSize(new Dimension(800, 800));