Saad A
Saad A

Reputation: 1147

Java : Draw Rectangles on mouse click

I want to draw a rectangle every time user clicks on the "Rectangle" button and then clicks on the JFrame based on the event x and y coordinates. I have a component class the draws the rectangle and I have another class that has JFrame mouse press listener.

My Code:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

import javax.swing.JComponent;


public class RectangleComponent extends JComponent
{

    Rectangle box;

    RectangleComponent()
    {
        box = new Rectangle(5, 10, 20, 30);
        repaint();
    }

    RectangleComponent(int x, int y)
    {
        box = new Rectangle(x, y, 20, 30);

    }

    public void paintComponent(Graphics g)
    {  
        // Recover Graphics2D
        Graphics2D g2 = (Graphics2D) g;

        // Change the color
        Color c = new Color(1.0F,0.0F,1.0F); 
        g2.setColor(c);

        // Draw a rectangle
        g2.draw(box);


    }

}


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Test2
{
    static boolean isPressed = false;

    public static void main(String[] args)
    {
        final JFrame frame = new JFrame();

        final int FRAME_WIDTH  = 400;
        final int FRAME_HEIGHT = 400;

        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setTitle("Test 2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        JPanel panel = new JPanel();
        frame.add(panel,BorderLayout.NORTH);


        final JButton btnRectangle = new JButton("Rectangle");
        panel.add(btnRectangle);

        class RectangleButtonListener implements ActionListener
        { 
            public void actionPerformed(ActionEvent event)
            {
                isPressed = true;
            }      
        }

        ActionListener rectButtonListener = new RectangleButtonListener();
        btnRectangle.addActionListener(rectButtonListener);


        class MousePressListener implements MouseListener
        {
            public void mousePressed(MouseEvent event)
            {
                int x = event.getX() ; 
                int y = event.getY() ;


                if(isPressed)
                {

                    RectangleComponent rc = new RectangleComponent(x, y); 
                    frame.add(rc);


                }


            }

            public void mouseReleased(MouseEvent event){}
            public void mouseClicked(MouseEvent event){}
            public void mouseEntered(MouseEvent event){}
            public void mouseExited(MouseEvent event){}
        }

        MousePressListener mListener = new MousePressListener();
        frame.addMouseListener(mListener);


        frame.setVisible(true);
    }

}

Now it seems to be doing what I want, but in very strange way. If I click rectangle and click on the frame I see nothing but then if I maximize the frame the rectangle appears where I click. Why is this happening and what is the fix?

Upvotes: 0

Views: 8509

Answers (3)

Jonah
Jonah

Reputation: 1003

To start off with, when using paintComponent() you need to Override it and call it's super method like so:

@Override
public void paintComponent(Graphics g)
{
    super.paintComponent(g);
}

Secondly, Here is your RectangleComponent Class with some slight modifications:

public class RectangleComponent extends JComponent
{
    int x, y;

    RectangleComponent(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Color c = new Color(1.0F,0.0F,1.0F);
        g.setColor(c);

        g.drawRect(x, y, 50, 50);
    }
}

I took the x and y variables and made them member variables so we can access them in the paintComponent() method. I also removed the whole "box" idea and did all the drawing and such in the paintCompnent()

There's also some slight modifications that you should make to your Test2 Class;

Personal recommendation, I suggest switching your drawing code to the mouseReleased event. Along with calling revalidate() and repaint() on your JFrame.

public void mouseReleased(MouseEvent event)
{
    int x = event.getXOnScreen();
    int y = event.getYOnScreen();

    if(isPressed)
    {
        RectangleComponent rc = new RectangleComponent(x, y);
        frame.add(rc);
        frame.revalidate();
        frame.repaint();
    }
}

My results:

Boxes!

Upvotes: 2

Saad A
Saad A

Reputation: 1147

I figured instead of adding new component upon click, why not just update a component that already exist by adding more content to it and then repainting it.

Here how this was fixed:

import javax.swing.JComponent ;

import java.awt.event.MouseListener ;
import java.awt.event.MouseEvent ;
import java.awt.Component;
import java.awt.Graphics2D ;
import java.awt.Graphics ;
import java.awt.Shape ;
import java.util.ArrayList ;

public class ShapeComponent extends JComponent
{
      private ArrayList<Shape> shapes ;

      public ShapeComponent(ArrayList<Shape> shapes1)
      {
          shapes = shapes1;
      }

      public void paintComponent(Graphics g)
      {  

          Graphics2D g2 = (Graphics2D) g;

          for (Shape shape : shapes)
          {
              g2.draw(shape);
          }

        }
}

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Test3 
{
    static boolean isPressed = false;
    static ArrayList<Shape> shapes = new ArrayList<Shape>() ;

    public static void main(String[] args)
    {
        final JFrame frame = new JFrame();

        final int FRAME_WIDTH  = 400;
        final int FRAME_HEIGHT = 400;

        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        frame.setTitle("Test 2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        JPanel panel = new JPanel();
        frame.add(panel,BorderLayout.NORTH);


        final JButton btnRectangle = new JButton("Rectangle");
        panel.add(btnRectangle);

        class RectangleButtonListener implements ActionListener
        { 
            public void actionPerformed(ActionEvent event)
            {
                isPressed = true;
            }      
        }

        ActionListener rectButtonListener = new RectangleButtonListener();
        btnRectangle.addActionListener(rectButtonListener);

        final JComponent component = new ShapeComponent(shapes) ;
        frame.add(component);


        class MousePressListener implements MouseListener
        {
            public void mousePressed(MouseEvent event)
            {
                int x = event.getX() ; 
                int y = event.getY() ;

                System.out.println("you have press the mouse at X : " + x + " and Y : " + y);

                if(isPressed)
                {
                    Rectangle rnew = new Rectangle(x, y, 20, 30);
                    shapes.add(rnew);
                    component.repaint();

                    System.out.println("the button is pressed");
                }
                else
                {
                    System.out.println("the button is NOT pressed");
                }

            }

            public void mouseReleased(MouseEvent event){}
            public void mouseClicked(MouseEvent event){}
            public void mouseEntered(MouseEvent event){}
            public void mouseExited(MouseEvent event){}
        }

        MousePressListener mListener = new MousePressListener();
        frame.addMouseListener(mListener);



        frame.setVisible(true);
    }
}

Upvotes: -1

djebeeb
djebeeb

Reputation: 191

Maximizing your frame calls repaint() automatically. It would probably be easiest to call repaint() after adding the RectangleComponent to the frame.

if(isPressed)
{    
    RectangleComponent rc = new RectangleComponent(x, y); 
    frame.add(rc);
    rc.repaint();
}

Upvotes: 1

Related Questions