0

I have this code in JAVA that draws a rectangle like the paint app when I drag my mouse on the panel. Every time I click and drag to make a new rectangle, the previous one disappears. I was wondering if there is a way for it to stay on the panel. And for there to be multiple rectangles, just like the paint app on windows.


import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

    public class DrawRect extends JPanel {

        int x, y, x2, y2;

        public static void main(String[] args) {
            JFrame f = new JFrame("Draw Box Mouse 2");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setContentPane(new DrawRect());
            f.setSize(300, 300);
            f.setVisible(true);
        }

        DrawRect() {
            x = y = x2 = y2 = 0; // 
            MyMouseListener listener = new MyMouseListener();
            addMouseListener(listener);
            addMouseMotionListener(listener);
        }

        public void setStartPoint(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public void setEndPoint(int x, int y) {
            x2 = (x);
            y2 = (y);
        }

        public void drawPerfectRect(Graphics g, int x, int y, int x2, int y2) {
            int px = Math.min(x,x2);
            int py = Math.min(y,y2);
            int pw=Math.abs(x-x2);
            int ph=Math.abs(y-y2);
            g.drawRect(px, py, pw, ph);
        }

        class MyMouseListener extends MouseAdapter {

            public void mousePressed(MouseEvent e) {
                setStartPoint(e.getX(), e.getY());
            }

            public void mouseDragged(MouseEvent e) {
                setEndPoint(e.getX(), e.getY());
                repaint();
            }

            public void mouseReleased(MouseEvent e) {
                setEndPoint(e.getX(), e.getY());
                repaint();
            }
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            drawPerfectRect(g, x, y, x2, y2);
        }

    }
yegu sanon
  • 39
  • 4
  • Sure. Save each rectangle in a java.util.List of java.awt.Rectangle objects. Draw the rectangles from the List. – Gilbert Le Blanc Feb 19 '21 at 00:05
  • `paintComponent` is called each time the panel needs to be updated, and replaces all the contents of the panel. You need to manage the list of objects you want to draw. – tgdavies Feb 19 '21 at 00:13

1 Answers1

1

There are a few useful things to remember writing Swing graphics programs:

  • paintComponent repaints the entire component every time it is called, so you need to draw everything that you want to appear. The operations you do with the Graphics object will only persist until the next call to paintComponent.
  • Graphics2D is more capable than Graphics. It draws nicely antialiased shapes with floating-point co-ordinates, various line styles and so on. The Graphics parameter to paintComponent is in fact always a Graphics2D instance and you can cast it to one without worrying.
  • The inheritance hierarchy of components is also a painting hierarchy, so you need to call super.paintComponent(g) at the start of your paintComponent method. See this question for more details.

So I've made some changes to you program:

  • Added a field, List<Rectangle2D> rectangles to remember the rectangles the user has created. A rectangle is added to this list each time the mouse button is raised.
  • Added a call to super.paintComponent
  • Used Graphics2D to draw the rectangles, with a more interesting line style (Stroke)
  • Changed your paintComponent to draw each of the rectangles in the list, plus the 'rubber-band' rectangle the user is currently drawing.

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

public class DrawRect extends JPanel {

    int x, y, x2, y2;
    // this is the list of all the rectangles the user has drawn so far
    List<Rectangle2D> rectangles = new ArrayList<>();

    public static void main(String[] args) {
        JFrame f = new JFrame("Draw Box Mouse 2");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new DrawRect());
        f.setSize(300, 300);
        f.setVisible(true);
    }

    DrawRect() {
        x = y = x2 = y2 = 0; //
        MyMouseListener listener = new MyMouseListener();
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }

    public void setStartPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void setEndPoint(int x, int y) {
        x2 = (x);
        y2 = (y);
    }

    // this creates a new rectangle object instead of drawing one
    public Rectangle2D makePerfectRect(int x, int y, int x2, int y2) {
        int px = Math.min(x,x2);
        int py = Math.min(y,y2);
        int pw=Math.abs(x-x2);
        int ph=Math.abs(y-y2);
        return new Rectangle2D.Float(px, py, pw, ph);
    }

    class MyMouseListener extends MouseAdapter {

        public void mousePressed(MouseEvent e) {
            setStartPoint(e.getX(), e.getY());
        }

        public void mouseDragged(MouseEvent e) {
            setEndPoint(e.getX(), e.getY());
            repaint();
        }

        public void mouseReleased(MouseEvent e) {
            setEndPoint(e.getX(), e.getY());
            // when the mouse is released, we add the current rectangle to our list
            rectangles.add(makePerfectRect(x,y,x2,y2));
            repaint();
        }
    }

    public void paintComponent(Graphics g) {
        // use Graphics2D, you can draw much nicer lines
        Graphics2D g2d = (Graphics2D) g;
        super.paintComponent(g);
        g.setColor(Color.RED);
        // draw the rectangle the user is currently drawing
        g2d.draw(makePerfectRect(x,y,x2,y2));
        g.setColor(Color.BLUE);

                Stroke oldStroke = g2d.getStroke();
        g2d.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0.0f));
        for (Rectangle2D r : rectangles) {
            g2d.draw(r);
        }
        g2d.setStroke(oldStroke); // restore the original Stroke
    }

}
tgdavies
  • 10,307
  • 4
  • 35
  • 40