Search code examples
javaswingpaintcomponent

Why won't the rectangle draw where I click?


Here is the class that draws the rectangle. It's supposed to use the static ints x,y for the components of the location of the rectangle to be draw, which are the x and y components from a mouse click. The x,y come from the Gui3 class from event.getX() and event.getY(). The program and all its methods work fine, the only problem is arising when the shape is drawn.

Class to draw the shape

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

public class DrawShapes extends JPanel {
    public static int x,y;
    public void paintComponent(Graphics g){
        g.setColor(Color.BLUE);
        g.fillRect(x,y,80,80);
    }
    public class GuiDemo extends Gui3{
        public GuiDemo(){
            x=x1;
            y=y1;
        }
        }

}

Main class that does everything else

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

public class Gui3 extends JFrame {
    private JPanel mousepanel;
    private JLabel statusbar;
    public static int x1=0, y1=0;
    public Gui3(){
        super("The title");

        mousepanel = new JPanel();
        mousepanel.setBackground(Color.WHITE);
        add(mousepanel, BorderLayout.CENTER);

        statusbar = new JLabel("Default");
        add(statusbar, BorderLayout.SOUTH);

        HandlerClass handler = new HandlerClass();
        mousepanel.addMouseListener(handler);
        mousepanel.addMouseMotionListener(handler);
    }   
    private class HandlerClass implements MouseListener, MouseMotionListener
        {
        @Override
        public void mouseClicked(MouseEvent event) {
            statusbar.setText(String.format("Clicked at %d, %d", event.getX(),event.getY()));

This is where the x and y components are received from

x1=event.getX();
y1=event.getY();

The components get passed to the DrawShapes class. The rectangle only gets draw in the corner. It's supposed to be draw wherever I click

enter image description here

                DrawShapes shapes = new DrawShapes();
                add(shapes);
            }
            @Override
            public void mousePressed(MouseEvent event){
                statusbar.setText("You pressed down the mouse");
            }

            @Override
            public void mouseReleased(MouseEvent event){
                statusbar.setText("You released the button");
            }
            @Override
            public void mouseEntered(MouseEvent event){
                statusbar.setText("You entered the area");
                mousepanel.setBackground(Color.RED);
            }
            @Override
            public void mouseExited(MouseEvent event){
                statusbar.setText("The mouse has left the window");
                mousepanel.setBackground(Color.WHITE);
            }
            //These are mouse motion events
            @Override
            public void mouseDragged(MouseEvent event){
                statusbar.setText("You are dragging the mouse");
            }
            @Override
            public void mouseMoved(MouseEvent event){
                statusbar.setText("You are moving the mouse");
            }
        }
    }

Solution

  • The reason you see the rectangle in the top-left is because x and y in DrawShapes are assigned only once, when GuiDemo is constructed; at that point in time, x1 and y1 are both initialized to 0. While x1 and y1 get reassigned upon click, this change is never propagated back to the DrawShapes class.

    I have a couple of recommendations:

    • Get rid of the static variables entirely. It's easier to just pass things from object to object. DrawShapes should have an x and a y, put I would make them private (who else needs them?) and non-static (in case you ever need more than one DrawShapes)
    • Add a setPosition method to DrawShapes, such that you have a way to communicate this position to the object that will draw the rectangle:

      public void setPosition(int newX, int newY) {
          this.x = newX;
          this.y = newY;
          repaint();
      }
      

      The repaint is important here (Java Swing manages a lot of drawing work for you, but you need to let it know when a redraw is needed if you are doing custom painting.)

    • Use that setPosition when a click occurs

      shapes.setPosition(event.getX(), event.getY());
      

    Caveat: Code above is untested, but I believe this will set you along the right way.