Search code examples
javaswingpaintcomponent

Rectangle is not drawn on top


I have a class "Map" which extends JPanel. I add it to a class that extends a JFrame.

public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int width = Math.abs(startX - endX);
        int height= Math.abs(startY - endY);
        g.setColor(Color.RED);
        g.fillRect(startX, startY, width, height);
    }

My class "Map" also contains a label with an image in it. If the image is smalled than the window, when I draw a rectangle it is seen. In short, it is under the label.


Solution

  • paintComponent is the "bottom" of the paint chain, so anything painted here will appear below everything else.

    A better solution might be to add the Map panel to the label (setting the JLabel's layout manager appropriately).

    Or, create a "base" panel, set it's layout manager to use a OverlayLayout manager and add the JLabel and Map panel to it.

    This will, of course, all depend on what it is you want to achieve...

    Updated with "Panel on Label" example

    Basically, this takes a JLabel, sets an icon (as the background image), set it's layout as BorderLayout and then adds a JPanel on to it.

    Remember, JPanel is opaque by default, so you need to make it transparent ;)

    Panel on label

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class OverlayLabel {
    
        public static void main(String[] args) {
            new OverlayLabel();
        }
    
        public OverlayLabel() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        try {
                            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                            ex.printStackTrace();
                        }
    
                        JLabel background = new JLabel(new ImageIcon(ImageIO.read(new File("/path/to/image"))));
                        background.setLayout(new BorderLayout());
                        background.add(new TestPane());
    
                        JFrame frame = new JFrame("Testing");
                        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        frame.add(background);
                        frame.pack();
                        frame.setLocationRelativeTo(null);
                        frame.setVisible(true);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                setOpaque(false);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics g2d = (Graphics2D) g.create();
                int x = (getWidth() - 20) / 2;
                int y = (getHeight() - 20) / 2;
                g2d.setColor(Color.RED);
                g2d.fillRect(x, y, 20, 20);
                g2d.dispose();
            }
    
        }
    
    }
    

    Updated with example of OverlayLayout

    OverlayLayout basically uses the components x/y alignment to make determinations about how best it should place the individual components

    OverlayLayout

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.OverlayLayout;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.LineBorder;
    
    public class OverlayLabel {
    
        public static void main(String[] args) {
            new OverlayLabel();
        }
    
        public OverlayLabel() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        try {
                            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                            ex.printStackTrace();
                        }
    
                        JLabel background = new JLabel(new ImageIcon(ImageIO.read(new File("/path/to/image"))));
                        background.setAlignmentX(0.5f);
                        background.setAlignmentY(0.5f);
    
                        JFrame frame = new JFrame("Testing");
                        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        frame.setLayout(new OverlayLayout(frame.getContentPane()));
                        frame.add(new TestPane());
                        frame.add(background);
                        frame.pack();
                        frame.setLocationRelativeTo(null);
                        frame.setVisible(true);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                setOpaque(false);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics g2d = (Graphics2D) g.create();
                int x = (getWidth() - 20) / 2;
                int y = (getHeight() - 20) / 2;
                g2d.setColor(Color.RED);
                g2d.fillRect(x, y, 20, 20);
                g2d.dispose();
            }
    
        }
    
    }
    

    And finally, if none of that is working for you, you could use JLayeredPane as the base, which will allow you to determine the z-order of each component...

    See How to use layered panes for more details...