Question

I am writing a program that allows a user to paint rectangles onto a JLabel, and show the intersection and union of these rectangles. I have setup the GUI for the class but am struggling to find a way to integrate the intersection and union methods from the rectangle class. I know these methods work when used separately from the GUI.

When I try to run the program I keep getting an IndexOutOfBoundsException and the drawn rectangles are cleared from the gui. The intersections of each rectangle should show up in a different color on the JLabel. I tried to debug the program and for some reason when I create two rectangles and store them in my array list many many rectangle objects of the same characteristics are being created.

For the union method, a new rectangle should be create that contains all of the rectangles on the inside.

RectangleFrame1:

public class RectangleFrame1 extends JFrame implements ActionListener
{


    JPanel buttonPanel;
    JButton saveImage;
    JButton clearImage;
    JCheckBox intersections;
    JCheckBox union;
    RectangleLabel drawingArea;
    boolean intersect = false;
    boolean uni = false;

    public RectangleFrame1()
    {
        super();
        setTitle("Rectangles");
        setSize(600,600);
        setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        buttonPanel = new JPanel();
        buttonPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        this.add(buttonPanel, BorderLayout.SOUTH);

        intersections = new JCheckBox("Draw Intersections");
        buttonPanel.add(intersections);
        intersections.addActionListener(this);
        intersections.setActionCommand("Intersections");

        union = new JCheckBox("Draw Union");
        buttonPanel.add(union);
        union.addActionListener(this);
        union.setActionCommand("Union");

        saveImage = new JButton("Save Image");
        saveImage.setMargin(new Insets(0,0,0,0));
        buttonPanel.add(saveImage);
        saveImage.addActionListener(this);
        saveImage.setActionCommand("Save Image");

        clearImage = new JButton("Clear Image");
        clearImage.setMargin(new Insets(0,0,0,0));
        buttonPanel.add(clearImage);
        clearImage.addActionListener(this);
        clearImage.setActionCommand("Clear Image");

        drawingArea = new RectangleLabel();
        drawingArea.setBorder(BorderFactory.createLineBorder(Color.blue));
        this.add(drawingArea, BorderLayout.CENTER);
        drawingArea.addMouseListener((MouseListener) drawingArea);
        drawingArea.addMouseMotionListener((MouseMotionListener) drawingArea);

    }

    @Override
    public void actionPerformed(ActionEvent arg0)
    {
        switch(arg0.getActionCommand())
        {
            case "Intersections":
            if(intersections.isSelected())
            {
                intersect = true;
            }
            else
            {
                intersect = false;
            }
            case "Union":
            if(union.isSelected())
            {
                uni = true;
            }
            else
            {
                uni = false;
            }
            case "Clear Image": drawingArea.clearImage();
            case "Save Image": drawingArea.saveImage();
        }

    }

    class RectangleLabel extends JLabel implements MouseListener, MouseMotionListener
    {

        Rectangle rectangle = null;
        int x, y, x2, y2;
        ArrayList<Rectangle> a = new ArrayList();
        int counter;
        public RectangleLabel()
        {
            super();
        }
        @Override
        public void mousePressed(MouseEvent arg0)
        {
            x = arg0.getX();
            y = arg0.getY();

            rectangle = new Rectangle(x, y, 0, 0);
        }

        @Override
        public void mouseDragged(MouseEvent arg0)
        {
            // TODO Auto-generated method stub
            x2 = arg0.getX();
            y2 = arg0.getY();

            if(rectangle.getX() > x2)
            {
                rectangle.setWidth(x-x2);
            }
            if(x2 > rectangle.getX())
            {
                rectangle.setWidth(x2-x);
            }
            if(y > y2)
            {
                rectangle.setHeight(y-y2);
            }
            if(y2 > y)
            {
                rectangle.setHeight(y2-y);
            }

            a.add(rectangle);
            counter++;
            repaint();

        }

        @Override
        public void mouseReleased(MouseEvent arg0)
        {
            repaint();
        }

        @Override
        public void mouseMoved(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseClicked(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            if(rectangle != null)
            {
                for(int i = 0; i < a.size(); i++)
                {
                    float thickness = 2;
                    ((Graphics2D) g).setStroke(new BasicStroke(thickness));
                    g.setColor(Color.BLUE);
                    g.drawRect(a.get(i).getX(), a.get(i).getY(), a.get(i).getWidth(), a.get(i).getHeight());
                    g.setColor(Color.gray);
                    g.fillRect(a.get(i).getX(), a.get(i).getY(), a.get(i).getWidth(), a.get(i).getHeight());
                }
            }

            if(intersect == true && counter > 0)
            {
                for(int h = 0; h < counter-1; h++)
                {
                    for(int j = 1; j < counter; j++)
                    {   if(a.get(h).overlaps(a.get(j)))
                        {
                            Rectangle rect = a.get(h).intersect(a.get(j));
                            g.setColor(Color.RED);
                            g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
                        }
                    }
                }
            }

            if(uni == true && counter > 0)
            {
                for(int h = 0; h < counter - 1; h++)
                {
                    for(int j = 1; j < counter; j++)
                    {
                        Rectangle rect = a.get(h).union(a.get(j));
                        g.setColor(Color.WHITE);
                        g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());

                    }
                }
            }
        }


        public void saveImage()
        {
            BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D aaaaa = image.createGraphics();
            aaaaa.setBackground(Color.WHITE);
            aaaaa.clearRect(0, 0, this.getWidth(), this.getHeight());
            this.paintAll(aaaaa);
            try
            {
                File output = new File("rectangle.png");
                ImageIO.write(image, "Rectangles", output);
            }
            catch(IOException ie)
            {

            }
        }
        public void clearImage()
        {
            a.clear();
            repaint();
        }

    }

}

Rectangle:

public class Rectangle
{


    private int x,y,width,height;

    public Rectangle(int x,int y,int width,int height)
    {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public Rectangle(Rectangle a)
    {
        this.x = a.x;
        this.y = a.y;
        this.width = a.width;
        this.height = a.height;
    }

    public String toString()
    {
        return "Start: ("+x+","+y+"), Width: "+width+", Height: "+height+"\n";
    }

    public int getX()
    {
        return x;
    }

    public int getY()
    {
        return y;
    }

    public int getWidth()
    {
        return width;
    }

    public int getHeight()
    {
        return height;
    }

    public void setX(int x)
    {
        this.x = x;
    }

    public void setY(int y)
    {
        this.y = y;
    }

    public void setWidth(int width)
    {
        this.width = width;
    }

    public void setHeight(int height)
    {
        this.height = height;
    }

    public int area()
    {
        return width*height;
    }

    public boolean overlaps(Rectangle a)
    {
        if ((x>a.x+a.width) || (a.x>x+width) || (y>a.y+a.height) || (a.y>y+height))
        {
            return false;
        }
        return true;
    }

    public Rectangle intersect(Rectangle a)
    {
        if (!overlaps(a))
            return null;

        int left,right,top,bottom;

        if (x<a.x)
            left = a.x;
        else
            left = x;

        if (y<a.y)
            bottom = a.y;
        else
            bottom = y;

        if ((x+width)<(a.x+a.width))
            right = x+width;
        else
            right = a.x+a.width;

        if ((y+height)<(a.y+a.height))
            top = y+height;
        else
            top = a.y+a.height;

        return new Rectangle(left,bottom,right-left,top-bottom);
    }

    public Rectangle union(Rectangle a)
    {
        int left,right,top,bottom;

        if (x<a.x)
            left = x;
        else
            left = a.x;

        if (y<a.y)
            bottom = y;
        else
            bottom = a.y;

        if ((x+width)<(a.x+a.width))
            right = a.x+a.width;
        else
            right = x+width;

        if ((y+height)<(a.y+a.height))
            top = a.y+a.height;
        else
            top = y+height;

        return new Rectangle(left,bottom,right-left,top-bottom);
    }
}
Was it helpful?

Solution

There are a number of problems...

You're mouseDragged event handler is adding the same Rectangle to the a ArrayList, over and over again, increasing the counter value along with it.

This is not required. All you need to do is add the Rectangle on the mousePressed event. When mouseReleased is called, you could evaluate the Rectangle to check if the size is greater than 0x0 and remove it if it's not (ie remove any Rectangle whose size is 0x0)

Don't rely on the counter variable, it's too easy for the value to become misaligned with the size of the a List. Instead, rely on a.size instead.

The switch statement in your ActionListener is evaluating the matching case, but also all the following cases below it. This is a feature of switch. If you don't want to evaluate the following cases, you need to add a break at the end of each case (or where ever you want to "break" the processing).

For example, when you click Draw Intersections, it is also evaluating Union, Clear Image and Save Image cases...

You could try using something like...

switch (arg0.getActionCommand()) {
    case "Intersections":
        intersect = intersections.isSelected();
        break;
    case "Union":
        uni = union.isSelected();
        break;
    case "Clear Image":
        drawingArea.clearImage();
        break;
    case "Save Image":
        drawingArea.saveImage();
        break;
}

instead...

Logic Errors in Painting Code...

There's also a logic area with your intersect paint code, where it is comparing a rectangle with itself, which ends up painting the whole rectangle.

Instead of

if (a.get(h).overlaps(a.get(j))) {

You might consider using

if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {

This is possibly occurring in you union painting logic as well, but I didn't really check that

Works fine for me...

enter image description here

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RectangleFrame1 extends JFrame implements ActionListener {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                RectangleFrame1 frame = new RectangleFrame1();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    JPanel buttonPanel;
    JButton saveImage;
    JButton clearImage;
    JCheckBox intersections;
    JCheckBox union;
    RectangleLabel drawingArea;
    boolean intersect = false;
    boolean uni = false;

    public RectangleFrame1() {
        super();
        setTitle("Rectangles");
        setSize(600, 600);
//        setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        buttonPanel = new JPanel();
        buttonPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        this.add(buttonPanel, BorderLayout.SOUTH);

        intersections = new JCheckBox("Draw Intersections");
        buttonPanel.add(intersections);
        intersections.addActionListener(this);
        intersections.setActionCommand("Intersections");

        union = new JCheckBox("Draw Union");
        buttonPanel.add(union);
        union.addActionListener(this);
        union.setActionCommand("Union");

        saveImage = new JButton("Save Image");
        saveImage.setMargin(new Insets(0, 0, 0, 0));
        buttonPanel.add(saveImage);
        saveImage.addActionListener(this);
        saveImage.setActionCommand("Save Image");

        clearImage = new JButton("Clear Image");
        clearImage.setMargin(new Insets(0, 0, 0, 0));
        buttonPanel.add(clearImage);
        clearImage.addActionListener(this);
        clearImage.setActionCommand("Clear Image");

        drawingArea = new RectangleLabel();
        drawingArea.setBorder(BorderFactory.createLineBorder(Color.blue));
        this.add(drawingArea, BorderLayout.CENTER);
        drawingArea.addMouseListener((MouseListener) drawingArea);
        drawingArea.addMouseMotionListener((MouseMotionListener) drawingArea);

    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        switch (arg0.getActionCommand()) {
            case "Intersections":
                intersect = intersections.isSelected();
                break;
            case "Union":
                uni = union.isSelected();
                break;
            case "Clear Image":
                drawingArea.clearImage();
                break;
            case "Save Image":
                drawingArea.saveImage();
                break;
        }
        repaint();
    }

    class RectangleLabel extends JLabel implements MouseListener, MouseMotionListener {

        Rectangle rectangle = null;
        int x, y, x2, y2;
        ArrayList<Rectangle> a = new ArrayList();

        public RectangleLabel() {
            super();
        }

        @Override
        public void mousePressed(MouseEvent arg0) {
            x = arg0.getX();
            y = arg0.getY();

            rectangle = new Rectangle(x, y, 0, 0);
            a.add(rectangle);
        }

        @Override
        public void mouseDragged(MouseEvent arg0) {
            // TODO Auto-generated method stub
            x2 = arg0.getX();
            y2 = arg0.getY();

            if (rectangle.getX() > x2) {
                rectangle.setWidth(x - x2);
            }
            if (x2 > rectangle.getX()) {
                rectangle.setWidth(x2 - x);
            }
            if (y > y2) {
                rectangle.setHeight(y - y2);
            }
            if (y2 > y) {
                rectangle.setHeight(y2 - y);
            }

            repaint();

        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            rectangle = null;
            repaint();
        }

        @Override
        public void mouseMoved(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseClicked(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Rectangle rect : a) {
                float thickness = 2;
                ((Graphics2D) g).setStroke(new BasicStroke(thickness));
                g.setColor(Color.BLUE);
                g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
                g.setColor(Color.gray);
                g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
            }

            if (intersect) {
                for (int h = 0; h < a.size() - 1; h++) {
                    for (int j = 1; j < a.size(); j++) {
                        if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {
                            Rectangle rect = a.get(h).intersect(a.get(j));
                            g.setColor(Color.RED);
                            g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
                        }
                    }
                }
            }

            if (uni) {
                for (int h = 0; h < a.size() - 1; h++) {
                    for (int j = 1; j < a.size(); j++) {
                        if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {
                            Rectangle rect = a.get(h).union(a.get(j));
                            g.setColor(Color.WHITE);
                            g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());

                        }
                    }
                }
            }
        }

        public void saveImage() {
            BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D aaaaa = image.createGraphics();
            aaaaa.setBackground(Color.WHITE);
            aaaaa.clearRect(0, 0, this.getWidth(), this.getHeight());
            this.paintAll(aaaaa);
            try {
                File output = new File("rectangle.png");
                ImageIO.write(image, "Rectangles", output);
            } catch (IOException ie) {

            }
        }

        public void clearImage() {
            a.clear();
            repaint();
        }

    }

    public class Rectangle {

        private int x, y, width, height;

        public Rectangle(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        public Rectangle(Rectangle a) {
            this.x = a.x;
            this.y = a.y;
            this.width = a.width;
            this.height = a.height;
        }

        public String toString() {
            return "Start: (" + x + "," + y + "), Width: " + width + ", Height: " + height + "\n";
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public int getWidth() {
            return width;
        }

        public int getHeight() {
            return height;
        }

        public void setX(int x) {
            this.x = x;
        }

        public void setY(int y) {
            this.y = y;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        public int area() {
            return width * height;
        }

        public boolean overlaps(Rectangle a) {
            if ((x > a.x + a.width) || (a.x > x + width) || (y > a.y + a.height) || (a.y > y + height)) {
                return false;
            }
            return true;
        }

        public Rectangle intersect(Rectangle a) {
            if (!overlaps(a)) {
                return null;
            }

            int left, right, top, bottom;

            if (x < a.x) {
                left = a.x;
            } else {
                left = x;
            }

            if (y < a.y) {
                bottom = a.y;
            } else {
                bottom = y;
            }

            if ((x + width) < (a.x + a.width)) {
                right = x + width;
            } else {
                right = a.x + a.width;
            }

            if ((y + height) < (a.y + a.height)) {
                top = y + height;
            } else {
                top = a.y + a.height;
            }

            return new Rectangle(left, bottom, right - left, top - bottom);
        }

        public Rectangle union(Rectangle a) {
            int left, right, top, bottom;

            if (x < a.x) {
                left = x;
            } else {
                left = a.x;
            }

            if (y < a.y) {
                bottom = y;
            } else {
                bottom = a.y;
            }

            if ((x + width) < (a.x + a.width)) {
                right = a.x + a.width;
            } else {
                right = x + width;
            }

            if ((y + height) < (a.y + a.height)) {
                top = a.y + a.height;
            } else {
                top = y + height;
            }

            return new Rectangle(left, bottom, right - left, top - bottom);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top