How to draw a rectangle on a java applet using mouse drag event and make it stay

22,704

Solution 1

Ok, after re-reading your question it seems you could care less to have multiple rectangles :)

Here is a solution with only one at a time (which is close to what you had to begin with):

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

public class MouseTracker4July extends JFrame implements MouseListener, MouseMotionListener {

    private static final long serialVersionUID = 1L;
    private final JLabel mousePosition;
    int x1, x2, y1, y2;
    int x, y, w, h;
    private final JLabel recStart;
    private final JLabel recStop;
    private final JLabel cords; // set up GUI and register mouse event handlers
    boolean isNewRect = true;

    public MouseTracker4July() {
        super( "Rectangle Drawer" );

        this.mousePosition = new JLabel();
        this.mousePosition.setHorizontalAlignment( SwingConstants.CENTER );
        getContentPane().add( this.mousePosition, BorderLayout.CENTER );

        JLabel text1 = new JLabel();
        text1.setText( "At the center the mouse pointer's coordinates will be displayed." );
        getContentPane().add( text1, BorderLayout.SOUTH );

        this.recStart = new JLabel();
        getContentPane().add( this.recStart, BorderLayout.WEST );

        this.recStop = new JLabel();
        getContentPane().add( this.recStop, BorderLayout.EAST );

        this.cords = new JLabel();
        getContentPane().add( this.cords, BorderLayout.NORTH );

        addMouseListener( this ); // listens for own mouse and
        addMouseMotionListener( this ); // mouse-motion events

        setSize( 800, 600 );
        setVisible( true );

    }

// MouseListener event handlers // handle event when mouse released immediately after press 
    public void mouseClicked( final MouseEvent event ) {
        this.mousePosition.setText( "Clicked at [" + event.getX() + ", " + event.getY() + "]" );

        repaint();
    }

// handle event when mouse pressed 
    public void mousePressed( final MouseEvent event ) {

        this.mousePosition.setText( "Pressed at [" + ( this.x1 = event.getX() ) + ", " + ( this.y1 = event.getY() ) + "]" );

        this.recStart.setText( "Start:  [" + this.x1 + ", " + this.y1 + "]" );

        this.isNewRect = true;

        repaint();
    }

// handle event when mouse released after dragging 
    public void mouseReleased( final MouseEvent event ) {
        this.mousePosition.setText( "Released at [" + ( this.x2 = event.getX() ) + ", " + ( this.y2 = event.getY() ) + "]" );

        this.recStop.setText( "End:  [" + this.x2 + ", " + this.y2 + "]" );

        repaint();
    }

// handle event when mouse enters area 
    public void mouseEntered( final MouseEvent event ) {
        this.mousePosition.setText( "Mouse entered at [" + event.getX() + ", " + event.getY() + "]" );
        repaint();
    }

// handle event when mouse exits area 
    public void mouseExited( final MouseEvent event ) {
        this.mousePosition.setText( "Mouse outside window" );
        repaint();
    }

// MouseMotionListener event handlers // handle event when user drags mouse with button pressed 
    public void mouseDragged( final MouseEvent event ) {
        this.mousePosition.setText( "Dragged at [" + ( this.x2 = event.getX() ) + ", " + ( this.y2 = event.getY() ) + "]" ); // call repaint which calls paint repaint();

        this.isNewRect = false;

        repaint();
    }

// handle event when user moves mouse 
    public void mouseMoved( final MouseEvent event ) {
        this.mousePosition.setText( "Moved at [" + event.getX() + ", " + event.getY() + "]" );
        repaint();
    }

    @Override
    public void paint( final Graphics g ) {
        super.paint( g ); // clear the frame surface 
        g.drawString( "Start Rec Here", this.x1, this.y1 );
        g.drawString( "End Rec Here", this.x2, this.y2 );

        int width = this.x1 - this.x2;
        int height = this.y1 - this.y2;

        this.w = Math.abs( width );
        this.h = Math.abs( height );
        this.x = width < 0 ? this.x1
            : this.x2;
        this.y = height < 0 ? this.y1
            : this.y2;

        if ( !this.isNewRect ) {
            g.drawRect( this.x, this.y, this.w, this.h );
        }

        this.cords.setText( "w = " + this.w + ", h = " + this.h );

    }

    public static void main( final String args[] ) {
        MouseTracker4July application = new MouseTracker4July();
        application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    }

} // end class MouseTracker

Solution 2

You need to store your drawn items in some data structure and ensure that each item in the structure is painted to the canvas on repaint.

Also, you need to add repaint to each of your mouse events.

Like this: (this assumes you want to keep ALL rect's) - you can go with a single rect by eliminating the arraylist and replacing with a single rect instance.

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

public class MouseTracker4July extends JFrame implements MouseListener, MouseMotionListener {

    private static final long serialVersionUID = 1L;
    private final JLabel mousePosition;
    int x1, x2, y1, y2;
    int w, h;
    private final JLabel recStart;
    private final JLabel recStop;
    private final JLabel cords; // set up GUI and register mouse event handlers
    private final ArrayList< Rectangle > rectangles = new ArrayList< Rectangle >();
    private boolean isNewRect = true;

    public MouseTracker4July() {
        super( "Rectangle Drawer" );

        this.mousePosition = new JLabel();
        this.mousePosition.setHorizontalAlignment( SwingConstants.CENTER );
        getContentPane().add( this.mousePosition, BorderLayout.CENTER );

        JLabel text1 = new JLabel();
        text1.setText( "At the center the mouse pointer's coordinates will be displayed." );
        getContentPane().add( text1, BorderLayout.SOUTH );

        this.recStart = new JLabel();
        getContentPane().add( this.recStart, BorderLayout.WEST );

        this.recStop = new JLabel();
        getContentPane().add( this.recStop, BorderLayout.EAST );

        this.cords = new JLabel();
        getContentPane().add( this.cords, BorderLayout.NORTH );

        addMouseListener( this ); // listens for own mouse and
        addMouseMotionListener( this ); // mouse-motion events

        setSize( 800, 600 );
        setVisible( true );

    }

// MouseListener event handlers // handle event when mouse released immediately after press 
    public void mouseClicked( final MouseEvent event ) {
        this.mousePosition.setText( "Clicked at [" + event.getX() + ", " + event.getY() + "]" );

        repaint();
    }

// handle event when mouse pressed 
    public void mousePressed( final MouseEvent event ) {

        this.mousePosition.setText( "Pressed at [" + ( this.x1 = event.getX() ) + ", " + ( this.y1 = event.getY() ) + "]" );

        this.recStart.setText( "Start:  [" + this.x1 + ", " + this.y1 + "]" );

        repaint();
    }

// handle event when mouse released after dragging 
    public void mouseReleased( final MouseEvent event ) {
        this.mousePosition.setText( "Released at [" + ( this.x2 = event.getX() ) + ", " + ( this.y2 = event.getY() ) + "]" );

        this.recStop.setText( "End:  [" + this.x2 + ", " + this.y2 + "]" );

        Rectangle rectangle = getRectangleFromPoints();

        this.rectangles.add( rectangle );

        this.w = this.h = this.x1 = this.y1 = this.x2 = this.y2 = 0;
        this.isNewRect = true;

        repaint();
    }

    private Rectangle getRectangleFromPoints() {
        int width = this.x1 - this.x2;
        int height = this.y1 - this.y2;
        Rectangle rectangle = new Rectangle( width < 0 ? this.x1
            : this.x2, height < 0 ? this.y1
            : this.y2, Math.abs( width ), Math.abs( height ) );

        return rectangle;
    }

// handle event when mouse enters area 
    public void mouseEntered( final MouseEvent event ) {
        this.mousePosition.setText( "Mouse entered at [" + event.getX() + ", " + event.getY() + "]" );
        repaint();
    }

// handle event when mouse exits area 
    public void mouseExited( final MouseEvent event ) {
        this.mousePosition.setText( "Mouse outside window" );
        repaint();
    }

// MouseMotionListener event handlers // handle event when user drags mouse with button pressed 
    public void mouseDragged( final MouseEvent event ) {
        this.mousePosition.setText( "Dragged at [" + ( this.x2 = event.getX() ) + ", " + ( this.y2 = event.getY() ) + "]" ); // call repaint which calls paint repaint();

        this.isNewRect = false;

        repaint();
    }

// handle event when user moves mouse 
    public void mouseMoved( final MouseEvent event ) {
        this.mousePosition.setText( "Moved at [" + event.getX() + ", " + event.getY() + "]" );
        repaint();
    }

    @Override
    public void paint( final Graphics g ) {
        super.paint( g ); // clear the frame surface 
        g.drawString( "Start Rec Here", this.x1, this.y1 );
        g.drawString( "End Rec Here", this.x2, this.y2 );

        Rectangle newRectangle = getRectangleFromPoints();
        if ( !this.isNewRect ) {
            g.drawRect( newRectangle.x, newRectangle.y, newRectangle.width, newRectangle.height );
        }

        for( Rectangle rectangle : this.rectangles ) {
            g.drawRect( rectangle.x, rectangle.y, rectangle.width, rectangle.height );
        }

        this.cords.setText( "w = " + this.w + ", h = " + this.h );

    }

    public static void main( final String args[] ) {
        MouseTracker4July application = new MouseTracker4July();
        application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    }

} // end class MouseTracker

Solution 3

Read up on these two Custom Painting Approaches. One approach is described above and the second approach shows how to use a BufferedImage. The example used for both approaches allows you to add multiple Rectangles to the frame.

Share:
22,704
Tyler
Author by

Tyler

Updated on July 05, 2022

Comments

  • Tyler
    Tyler almost 2 years

    I have my program that can draw rectangles. I have two problems I can't solve. After I draw the rectangle it won't stay. The only code I have that clears the canvas in under paint, repaint is only called on mouse drag. Why when I mouse release or mouse move does my canvas clear. The second thing isn't as much a problem, but something I can't figure out, when either the height or width of my rectangle is negative the rectangle is filled in black.

    package pracpapp2;
    
    
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class MouseTracker4July extends JFrame
       implements MouseListener, MouseMotionListener {
    
    
      private static final long serialVersionUID = 1L;
      private JLabel mousePosition;
      int x, y;
      int x1, x2, y1, y2;
      int w, h;
      private JLabel recStart;
      private JLabel recStop;
      private JLabel cords;
       // set up GUI and register mouse event handlers
       public MouseTracker4July()
       {
          super( "Rectangle Drawer" );
    
          mousePosition = new JLabel();
          mousePosition.setHorizontalAlignment(SwingConstants.CENTER);
          getContentPane().add( mousePosition, BorderLayout.CENTER );
    
    
          JLabel text1 = new JLabel();
          text1.setText( "At the center the mouse pointer's coordinates will be displayed." );
          getContentPane().add( text1, BorderLayout.SOUTH );
    
          recStart = new JLabel();
          getContentPane().add(recStart, BorderLayout.WEST);
    
          recStop = new JLabel();
          getContentPane().add(recStop, BorderLayout.EAST);
    
          cords = new JLabel();
          getContentPane().add(cords, BorderLayout.NORTH);
    
    
          addMouseListener( this );        // listens for own mouse and
          addMouseMotionListener( this );  // mouse-motion events
    
          setSize( 800, 600 );
          setVisible( true );
       }
    
       // MouseListener event handlers
       // handle event when mouse released immediately after press
       public void mouseClicked( MouseEvent event )
       {
          mousePosition.setText( "Clicked at [" + event.getX() +
             ", " + event.getY() + "]" );
       }
    
       // handle event when mouse pressed
       public void mousePressed( MouseEvent event )
       {
    
          mousePosition.setText( "Pressed at [" +(x1 = event.getX()) +
             ", " + (y1 = event.getY()) + "]" );
    
          recStart.setText( "Start:  [" + x1 +
             ", " + y1 + "]" );
       }
    
       // handle event when mouse released after dragging
       public void mouseReleased( MouseEvent event )
       {
         mousePosition.setText( "Released at [" +(x2 = event.getX()) +
             ", " + (y2 = event.getY()) + "]" );
    
         recStop.setText( "End:  [" + x2 +
             ", " + y2 + "]" );
    
       }
    
       // handle event when mouse enters area
       public void mouseEntered( MouseEvent event )
       {
          mousePosition.setText( "Mouse entered at [" + event.getX() +
             ", " + event.getY() + "]" );
       }
    
       // handle event when mouse exits area
       public void mouseExited( MouseEvent event )
       {
          mousePosition.setText( "Mouse outside window" );
       }
    
       // MouseMotionListener event handlers
       // handle event when user drags mouse with button pressed
       public void mouseDragged( MouseEvent event )
       {
          mousePosition.setText( "Dragged at [" + (x = event.getX()) + 
             ", " + (y = event.getY()) + "]" );
          // call repaint which calls paint
          repaint();
    
       }
    
       // handle event when user moves mouse
       public void mouseMoved( MouseEvent event )
       {
          mousePosition.setText( "Moved at [" + event.getX() +
             ", " + event.getY() + "]" );
       }
    
       public void paint(Graphics g)
       {
          super.paint(g); // clear the frame surface
          g.drawString("Start Rec Here", x1, y1);
          g.drawString("End Rec Here", x, y);
    
          w = x1 - x;
          h = y1 - y;
          w = w * -1;
          h = h * -1;
    
          g.drawRect(x1, y1, w, h);
    
          cords.setText( "w = " + w + ", h = " + h);
       }
    
       public static void main( String args[] )
       { 
          MouseTracker4July application = new MouseTracker4July();
          application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
       }
    
    } // end class MouseTracker
    
  • Tyler
    Tyler almost 15 years
    This is my first time programming graphically. How could I store the entire rectangle. I already have the rectangle parts (x, y, w, h) stored as int, then the rectangle is being drawn, but it's my integers are constantly updating, I'm not sure how to store them to something static that can be held on the canvas.
  • camickr
    camickr almost 15 years
    Custom painting should be done on a JPanel or JComponent, not on the actual JFrame and the paintComponent() method should be overriden, not the paint() method.
  • javamonkey79
    javamonkey79 almost 15 years
    @camickr - I agree, but for sake of understanding the problem I don't know that it will help Tyler in this insance (in the long run, yes).
  • javamonkey79
    javamonkey79 almost 15 years
    @Tyler: Look at the example I reposted. It has an arraylist of rect's to draw - this will allow the rect's to be stored. If you only want 1 rect then get rid of the list and keep a single rect. OR - you can keep just the x,y,w,h stuff - depends on what you want to do.
  • Tyler
    Tyler almost 15 years
    Thanks, I checked out your example, I know it works, I'm just trying to figure out how everything works (new java programmer). Anyways, I appreciate the help, but it's late and code is starting to melt my brain. I'll hit it back up tomorrow. Thanks, again.
  • Tyler
    Tyler almost 15 years
    That's exactly what I needed, I knew I was close, I just couldn't figure out how to finish the thing. The math.abs is cool because it keeps my width and height positive . Thanks a ton. One more question, is all the "this." good form or personal preference? I'm just curious because since I'm only using one JFrame isn't it redundant? Thanks again.
  • camickr
    camickr almost 15 years
    There is a lot of flicker every time I drag the mouse around, which is caused by overriding the paint() method of the frame as I suggested earlier.
  • javamonkey79
    javamonkey79 almost 15 years
    Personally, I would say that the 'this' usage is a bit of preference - there are others who would militantly disagree. Glad to help.