Search code examples
javaswingjframejlayeredpaneglasspane

Jframe - Drawing Rectangles not working


I have this code which is meant to draw a rectangle over a preloaded image, but it doesn't work.

When i add the drawing class to the frame, it overwrites the image, meaning i can't see my preloaded image, but it still allows me to draw the rectangles.

Also, instead of putting the jframe in the middle of my screen, it puts it in the top right hand corner and i have to maximize it to see the frame.

The code:

public class defineArea {

public static void main(String[] args) throws IOException {

    displayImage();
}

private static void displayImage() throws IOException {

    BufferedImage image = ImageIO.read(new File("C:\\Users\\Rusty\\Desktop\\temp\\Test_PDF-1.png"));
    ImageIcon icon = new ImageIcon(image);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel lbl = new JLabel();
    lbl.setIcon(icon);
    JScrollPane jsp = new JScrollPane(lbl);
    frame.add(jsp);
    frame.add(new paintRectangles());
    frame.pack();
    frame.setVisible(true);

}

public static class paintRectangles extends JComponent {
    ArrayList<Shape> shapes = new ArrayList<Shape>();
    Point startDrag, endDrag;

    public paintRectangles() throws IOException {

        this.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                startDrag = new Point(e.getX(), e.getY());
                endDrag = startDrag;
                repaint();
            }

            public void mouseReleased(MouseEvent e) {
                Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
                shapes.add(r);
                startDrag = null;
                endDrag = null;
                repaint();
            }
        });

        this.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                endDrag = new Point(e.getX(), e.getY());
                repaint();
            }
        });
    }

    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Color[] colors = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK };
        int colorIndex = 0;

        g2.setStroke(new BasicStroke(2));
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));

        for (Shape s : shapes) {
            g2.setPaint(Color.BLACK);
            g2.draw(s);
            g2.setPaint(colors[(colorIndex++) % 6]);
            g2.fill(s);
        }

        if (startDrag != null && endDrag != null) {
            g2.setPaint(Color.LIGHT_GRAY);
            Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
            g2.draw(r);
            System.out.println(r.getBounds2D());
        }
    }
}

private static Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
    return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}

}

Can anyone help? I'm basically trying to get the 2d Rectangle co-ordinates from the drawn rectangle (as per the system out getbounds2d).

if you remove frame.add(new paintRectangles());, you can see how the frame is meant to look (but without the ability to draw rectangles)


Solution

  • You could add paintRectangles (which should be PaintRectangles btw) to the JLayeredPane.
    The solution is not ideal but it is working.
    It worth a test drive to get to know this option, if nothing else :

    public class DefineArea {
    
        public static void main(String[] args) throws IOException {
    
            displayImage();
        }
        private static void displayImage() throws IOException {
    
            //  URL url = new URL("http://www.digitalphotoartistry.com/rose1.jpg");
            //    BufferedImage image = ImageIO.read(url);
            //    ImageIcon icon= new ImageIcon(image);
    
            URL url = DefineArea.class.getResource("image.jpg");
            BufferedImage image = ImageIO.read(url);
            ImageIcon icon = new ImageIcon(image);
    
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JLabel lbl = new JLabel();
            lbl.setIcon(icon);
    
            JScrollPane jsp = new JScrollPane(lbl);
            frame.add(jsp);
    
            //add glass pane to layered pane
            JComponent glass = new paintRectangles();
            JLayeredPane lp = frame.getLayeredPane();
            int w = icon.getIconWidth(); int h = icon.getIconHeight();
            // Size is needed here, as there is no layout in lp
            //to make it useful you need to dynamically adjust glass size
            glass.setSize(w,h);
            lp.add(glass);
    
            frame.pack();
            frame.setVisible(true);
        }
    
        public static class paintRectangles extends JComponent {
            ArrayList<Shape> shapes = new ArrayList<>();
            Point startDrag, endDrag;
    
            public paintRectangles() throws IOException {
    
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        System.out.println("mousePressed");
                        startDrag = new Point(e.getX(), e.getY());
                        endDrag = startDrag;
                        repaint();
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
                        shapes.add(r);
                        startDrag = null;
                        endDrag = null;
                        repaint();
                    }
                });
    
                addMouseMotionListener(new MouseMotionAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        endDrag = new Point(e.getX(), e.getY());
                        repaint();
                    }
                });
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Color[] colors = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK };
                int colorIndex = 0;
    
                g2.setStroke(new BasicStroke(2));
                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
    
                for (Shape s : shapes) {
                    g2.setPaint(Color.BLACK);
                    g2.draw(s);
                    g2.setPaint(colors[(colorIndex++) % 6]);
                    g2.fill(s);
                }
    
                if ((startDrag != null) && (endDrag != null)) {
                    g2.setPaint(Color.LIGHT_GRAY);
                    Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
                    g2.draw(r);
                    System.out.println(r.getBounds2D());
                }
            }
        }
    
        private static Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
            return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2),
                                                Math.abs(x1 - x2), Math.abs(y1 - y2));
        }
    }
    

    For more information see How to Use Layered Panes