How to absolutely position a JPanel over another JPanel with setLayout(null) and a background image?

Exac picture Exac · Jun 7, 2012 · Viewed 13.7k times · Source

I'm working with JFrames in Java, specifically with absolutely positioned elements that need to overlap. I understand that to overlay components, one should make a JPanel (with setOpacity(false);), and position it with either setBounds(x,y,x2,y2); or setPosition(x,y) & setSize(x,y). Unfortunately the panels act like CSS's inline-divs; they take up only the needed amount of room on their line, and do not stack.

This is the code I have so far, but it doesn't seem to act like I'd imagine it would:

class Login extends JFrame {
    private JPanel         backgroundpanel;
    private JPanel         panel;
    private JPanel         panel2;
    private JTextField     usernameBox;
    private JPasswordField passwordBox;
    private JButton        button;
    private int            height = 319;
    private int            width  = 452;
    private ImageIcon      ii     = new ImageIcon("special-window-BG.png");
    private JLabel         image;

    public Login() {
        setLayout(null);
        setTitle("Login");
        setSize(width,height);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);

        buildPanel();

        add(backgroundpanel);
        setVisible(true);
    }

    private void buildPanel() {
        usernameBox = new JTextField(20);
        passwordBox = new JPasswordField(20);
        button = new JButton("Login");
        image = new JLabel(ii);

        backgroundpanel = new JPanel();
        panel = new JPanel();
        panel2 = new JPanel();

        backgroundpanel.add(panel);
        backgroundpanel.add(panel2);
        backgroundpanel.add(image);

        panel.setBackground(Color.red);
        panel.setBounds(0, 0, 10, 10);
        panel.setOpaque(false);

        panel2.setBackground(Color.blue);
        panel2.setBounds(0, 0, 10, 10);
        panel2.setOpaque(false);

        panel.add(passwordBox);
        panel2.add(button);

        backgroundpanel.setOpaque(false);
        backgroundpanel.isOptimizedDrawingEnabled();
        backgroundpanel.setBounds(0, 0, width, height);

...cot'd, however unnecessary.

So basically, I'd like to know how to absolutely position JPanels (or JComponents, if that's simpler) over a JPanel with a background-image.

Thanks for taking a look at this question, I've spent far too much time on this method; the commented-out code extends nearly 500 lines passed what I posted, so I have nowhere else to turn to. The image below shows a crude illustration of what I'm trying to accomplish, I'm not sure if I'actually come close to getting it yet, because sometimes the JComponents seem to disappear as if they're behind the background image, however I'd like to find the simple solution that's most likely right in front of my eyes!

http://i.stack.imgur.com/revz8.jpg

Answer

Andrew Thompson picture Andrew Thompson · Jun 7, 2012

I'd like to find the simple solution that's most likely right in front of my eyes!

Something like this?

LoginPanel

import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class LoginPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    BufferedImage image;

    LoginPanel(BufferedImage image) {
        super(new GridBagLayout());

        this.image = image;

        JPanel controls = new JPanel(new BorderLayout(15,35));
        controls.setOpaque(false);
        controls.setBorder(new EmptyBorder(110,0,0,0));

        JPanel fields = new JPanel(new GridLayout(0,1,30,30));
        fields.setOpaque(false);
        controls.add(fields, BorderLayout.CENTER);
        fields.add(new JTextField(20));
        fields.add(new JPasswordField(20));

        JPanel button = new JPanel(new GridBagLayout());
        button.setOpaque(false);
        controls.add(button, BorderLayout.PAGE_END);
        button.add(new JButton("Log In"));

        Dimension prefSize = new Dimension(image.getWidth(),image.getHeight());
        setPreferredSize(prefSize);

        add(controls);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
    }

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/revz8.jpg");
        final BufferedImage image = ImageIO.read(url); 
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                LoginPanel p = new LoginPanel(image);
                JOptionPane.showMessageDialog(null, p);
            }
        });
    }
}