Search code examples
javaswingjframejpaneljlabel

Background JSwing Image Loading Oddly


enter image description here enter image description here

enter image description here

enter image description here

I can't seem to figure out how I would add in a background WITH all of my panels showing.

I tried to set the JFrame content pane as a label with an imageicon and the frame does show, it just doesn't show the image like above.

This is the code that I've used.

frame.setContentPane(new JLabel(new ImageIcon("res/Wallpaper.png")));

The second attempt I've used is to ADD (not set) an image into the content pane of the frame. This did not work as shown in the second picture above and it only shows the panels but no background. The code is on the bottom.

frame.getContentPane().add(new JLabel(new ImageIcon("res/Wallpaper.png")));

The third attempt I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane. This does not work and instead turns my screen blank.

Here is the code I've used and the class code is in the 1st answer of this link Setting background images in JFrame. The result is the 3rd image of this post.

        File img = new File("res/Wallpaper.png");

    BufferedImage myImage;
    try {
        myImage = ImageIO.read(img);
        frame.setContentPane(new ImagePanel(myImage));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

The 4th attempt I've tried is adding the picture into the main panel that fills up the screen. This does not work at all and instead breaks the image in half so half of the screen has the image half doesn't.

Here is the code I've used for my 4th attempt. The result is the 4th last image on the top.

        BufferedImage myPicture;
    try {
        myPicture = ImageIO.read(new File("res/Wallpaper.png"));
        JLabel picLabel = new JLabel(new ImageIcon(myPicture));
        pMain.add(picLabel);
    } catch (IOException e) {
        e.printStackTrace();
    }

I'm not sure why the JPanels aren't showing up.

I know that in the 1st example when you set the frame as a JLabel it gives it a null layout but that was the only way I could find to DISPLAY the image.

I would like to somehow add the panels ontop of the frame with that background but after reading numerous threads I could not find out how.

If anyone does find out, please post the code and explain if you can. I also have the class get the system class theme that sets it into the theme of what the computer is using. Ex. I am using a windows operating system so it shows it kind of like my operating system.

This thread is not a duplicate. In other threads they only have a frame but in my thread I have several panels that aren't showing for some particular reason.

EDIT: I don't know what's up, I tried to use this thread Setting background images in JFrame but I had no luck.

The 1st method it gave me I tried and then instead of showing anything it showed nothing at all, no picture no components nothing at all. In case if you need more information I have: 4 JPanels on the bottom of the screen, I also have a border surrounding my window but doesn't show up in the 1st window. I also have borders surrounding my panels too.

So the 1st method I've tried setting it on the content pane, image loads but all of the components are gone.

2nd method I've tried adding it into the content pane but yet again with no luck and I get a panel with no background.

3rd method I've tried is creating a separate class and overriding the paintComponent method and adding an image to the constructor of it then placing this object of the class into the setcontentPane() parameter of the frame. Does not work at all, all I get is a blank frame.

Code I am using for my frame:

public class LoginScreen {

JCheckBox remember_User;
JButton login, create_Account, forums, faqs;
Border whiteLine;
JTextField userField;
JFormattedTextField passField;

private void createView() {
    // Created essential details for the frame
    JFrame frame = new JFrame();
    frame.setTitle("Name of the game");
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Defining panels and a constraint on the bottomPanel.
    // More info - Total amt of panels: 5
    // pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in
    // bottomPanel
    // bottom panel is in pMain
    // Giving panels some attributes like backgrounds and borders
    JPanel pMain = new JPanel(new BorderLayout());
    pMain.setBorder(BorderFactory.createMatteBorder(3, 3, 6, 3,
            Color.DARK_GRAY));
    frame.getContentPane().add(pMain);

    whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);

    JPanel pLogin = new JPanel(new GridBagLayout());
    pLogin.setBackground(Color.cyan);
    pLogin.setPreferredSize(new Dimension(400, 250));
    pLogin.setBorder(whiteLine);

    JPanel pInfo = new JPanel(new GridBagLayout());
    pInfo.setBackground(Color.green);
    pInfo.setPreferredSize(new Dimension(200, 100));
    pInfo.setBorder(whiteLine);

    JPanel bottomCompPanel = new JPanel(new GridBagLayout());
    GridBagConstraints bGBC = new GridBagConstraints();
    bGBC.gridx = 0;
    bGBC.gridy = 0;
    bGBC.insets = new Insets(0, 20, 0, 0);
    bGBC.anchor = GridBagConstraints.PAGE_END;

    bottomCompPanel.add(pLogin, bGBC);
    bGBC.gridx++;
    bottomCompPanel.add(pInfo, bGBC);

    JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

    bottomPanel.add(bottomCompPanel);
    pMain.add(bottomPanel, BorderLayout.SOUTH);
    frame.setVisible(true);
}

public static void main(String[] args) {
    LoginScreen login = new LoginScreen();
    login.createView();
}

}

POST UPDATE 2: Here is the code that I've used using @peeskillet's 1st method. It works sort of but it gives me the same results as the 3rd photo, a cut off picture. P.S I add the panels down at the bottom to my JLabel at the end.

private void createView() {

    //Created essential details for the frame
    JFrame frame = new JFrame();
    frame.setTitle("Name of the game");
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);

    JLabel background = new JLabel(new ImageIcon("res/Wallpaper.png"));
    background.setLayout(new BorderLayout());
    frame.setContentPane(background);


    //Defining panels and a constraint on the bottomPanel. 
    //More info - Total amt of panels: 5
    //pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in bottomPanel
    //bottom panel is in pMain
    //Giving panels some attributes like backgrounds and borders

    whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);

    JPanel pLogin = new JPanel(new GridBagLayout());
    pLogin.setBackground(Color.cyan);
    pLogin.setPreferredSize(new Dimension(400,250));
    pLogin.setBorder(whiteLine);

    JPanel pInfo = new JPanel(new GridBagLayout());
    pInfo.setBackground(Color.green);
    pInfo.setPreferredSize(new Dimension(200,100));
    pInfo.setBorder(whiteLine);

    JPanel bottomCompPanel = new JPanel(new GridBagLayout());

    GridBagConstraints bGBC = new GridBagConstraints();
    bGBC.gridx = 0;
    bGBC.gridy = 0;
    bGBC.insets = new Insets(0,20,0,0);
    bGBC.anchor = GridBagConstraints.PAGE_END;

    bottomCompPanel.add(pLogin, bGBC);
    bGBC.gridx++;
    bottomCompPanel.add(pInfo, bGBC);

    JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

    bottomPanel.add(bottomCompPanel);
    background.add(bottomPanel, BorderLayout.SOUTH);

Solution

  • "I tried to set the JFrame content pane as a label with an imageicon"

    You need to set the layout on the JLabel. It will be null be default.

    import java.awt.*;
    import java.net.URL;
    import javax.swing.*;
    import javax.swing.border.Border;
    
    public class BackgroundImage {
    
        private static final String IMG = "https://i.sstatic.net/JEoYs.jpg";
    
        private void init() throws Exception {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            JLabel background = new JLabel(new ImageIcon(new URL(IMG)));
            background.setLayout(new GridBagLayout());
            background.add(loginPanel());
            f.setContentPane(background);
    
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        private JPanel loginPanel() {
            Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
            JPanel pLogin = new JPanel(new GridBagLayout());
            pLogin.setBackground(Color.cyan);
            pLogin.setPreferredSize(new Dimension(400, 250));
            pLogin.setBorder(whiteLine);
            return pLogin;
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                try {
                    new BackgroundImage().init();
                } catch (Exception ex) {}
            });
        }
    }
    

    enter image description here

    "I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane"

    Should be paintComponent (no "s"), but just like with JLabel, you need to set the layout. JComponent layout is null be default. You also need to give it a preferred size when painting.

    import java.awt.*;
    import java.net.URL;
    import javax.swing.*;
    import javax.swing.border.Border;
    
    public class BackgroundImage {
    
        private static final String IMG = "https://i.sstatic.net/JEoYs.jpg";
    
        private void init() throws Exception {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
            background.setLayout(new GridBagLayout());
            background.add(loginPanel());
            f.setContentPane(background);
    
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        private JPanel loginPanel() {
            Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
            JPanel pLogin = new JPanel(new GridBagLayout());
            pLogin.setBackground(Color.cyan);
            pLogin.setPreferredSize(new Dimension(400, 250));
            pLogin.setBorder(whiteLine);
            return pLogin;
        }
    
        class BackgroundComponent extends JComponent {
            public ImageIcon background;
            public BackgroundComponent(ImageIcon background) {
                this.background = background;
            }
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(background.getIconWidth(), background.getIconHeight());
            }
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(background.getImage(),
                            0, 0,
                            background.getIconWidth(), 
                            background.getIconHeight(), this);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                try {
                    new BackgroundImage().init();
                } catch (Exception ex) {}
            });
        }
    }
    

    enter image description here

    Using (extending) JPanel instead of JComponent would be similar except JPanel does have a default layout which is FlowLayout.


    UPDATE

    To get your desired layout, you need to play around with the different layout managers. The combination I used is

    Outer (main panel)     -- BorderLayout
    Bottom (bottom panel)  -- BoxLayout inside (south) of outer layout
    

    For the BorderLayout, you need to make sure the panel opaque property is set to false, as BorderLayout will stretch the panel and cover the background.

    For the BoxLayout, you need to make sure to set the maximum size and the preferred size

    import java.awt.*;
    import java.net.URL;
    import javax.swing.*;
    import javax.swing.border.Border;
    
    public class BackgroundImage {
    
        private static final String IMG = "https://i.sstatic.net/JEoYs.jpg";
        private final Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
    
    
        private void init() throws Exception {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
            background.setLayout(new BorderLayout());
            background.add(bottomPanel(), BorderLayout.SOUTH);
            f.setContentPane(background);
    
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        private JPanel bottomPanel() {
            JPanel bottomPanel = new JPanel();
            bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            BoxLayout layout = new BoxLayout(bottomPanel, BoxLayout.X_AXIS);
            bottomPanel.setLayout(layout);
            bottomPanel.setOpaque(false);
            bottomPanel.add(Box.createHorizontalGlue());
            bottomPanel.add(loginPanel());
            bottomPanel.add(Box.createRigidArea(new Dimension(10, 0)));
            bottomPanel.add(infoPanel());
            return bottomPanel;
        }
    
        private JPanel infoPanel() {
            JPanel pInfo = new JPanel(new GridBagLayout());
            pInfo.setAlignmentY(Component.BOTTOM_ALIGNMENT);
            pInfo.setBackground(Color.green);
            pInfo.setMaximumSize(new Dimension(200, 100));
            pInfo.setPreferredSize(new Dimension(200, 100));
            pInfo.setBorder(whiteLine);
            return pInfo;
        }
    
        private JPanel loginPanel() {
            JPanel pLogin = new JPanel(new GridBagLayout());
            pLogin.setAlignmentY(Component.BOTTOM_ALIGNMENT);
            pLogin.setBackground(Color.cyan);
            pLogin.setPreferredSize(new Dimension(400, 250));
            pLogin.setMaximumSize(new Dimension(400, 250));
            pLogin.setBorder(whiteLine);
            return pLogin;
        }
    
        class BackgroundComponent extends JComponent {
    
            public ImageIcon background;
    
            public BackgroundComponent(ImageIcon background) {
                this.background = background;
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(background.getIconWidth(), background.getIconHeight());
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(background.getImage(),
                        0, 0,
                        background.getIconWidth(),
                        background.getIconHeight(), this);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                try {
                    new BackgroundImage().init();
                } catch (Exception ex) {
                }
            });
        }
    }
    

    enter image description here

    For more information about using the different layout managers, see