2

I need to set a background image in my program. The structure of the main GUI is:

JFrame that contains - JPanel with BoxLayou that contains... etc

i need to put an image behind the first JPanel, but I don't know how.

i wrote this code:

JPanel background = new JPanel();
JLabel labl = new JLabel("This is a dummy label this is a dummy label");
background.add(labl);
// TODO insert an image in background.
Component VERT_RA = Box.createRigidArea(new Dimension(0, 10));
Component HORI_RA = Box.createRigidArea(new Dimension(10, 0));
JPanel main = new JPanel();
main.setLayout(new BoxLayout(main, BoxLayout.PAGE_AXIS));
add(background);
add(main);
main.setOpaque(false);
main.add(VERT_RA);
JPanel a = new JPanel();
a.setLayout(new BoxLayout(a, BoxLayout.LINE_AXIS));
main.add(a);
main.add(VERT_RA);
a.add(HORI_RA);
JPanel services = new JPanel();
services.setLayout(new BoxLayout(services, BoxLayout.PAGE_AXIS));
a.add(services);
a.add(HORI_RA);
JPanel right = new JPanel();
right.setLayout(new BoxLayout(right, BoxLayout.PAGE_AXIS));
a.add(right);
a.add(HORI_RA);     
JLabel lbl = new JLabel("SERVIZI");
lbl.setFont(new Font("SansSerif", Font.BOLD, 30));
lbl.setAlignmentX(Component.CENTER_ALIGNMENT);
lbl.setPreferredSize(new Dimension(100, 100));      
services.add(lbl);

but if I run it I can see only the "main" JPanel (the "SERVIZI" label). I can only see background JPanel if I specify a setSize(x,y) method.

Is there any way to add a background image to my layout, without having to specify dimensions?

I also tried with setLayou(null) but i had to specify dimensions for all components by hand (not useful).

Gianmarco
  • 2,536
  • 25
  • 57

3 Answers3

4

You simply have to override the getPreferredSize() method for the respective JPanel, and make it return some valid Dimension Object. I guess this example might can help you in that direction :

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class PaintingExample
{
    private CustomPanel contentPane;
    private JTextField userField;
    private JPasswordField passField;
    private JButton loginButton;

    private void displayGUI()
    {
        JFrame frame = new JFrame("Painting Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        contentPane = new CustomPanel();        

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new PaintingExample().displayGUI();
            }
        });
    }
}

class CustomPanel extends JPanel
{
    private BufferedImage image;

    public CustomPanel()
    {
        setOpaque(true);
        setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
        try
        {
            /*
             * Since Images are Application Resources,
             * it's always best to access them in the
             * form of a URL, instead of File, as you are doing.
             * Uncomment this below line and watch this answer
             * of mine, as to HOW TO ADD IMAGES TO THE PROJECT
             * https://stackoverflow.com/a/9866659/1057230
             * In order to access images with getClass().getResource(path)
             * here your Directory structure has to be like this
             *                 Project
             *                    |
             *         ------------------------
             *         |                      |
             *        bin                    src
             *         |                      |
             *     ---------             .java files             
             *     |       |                   
             *  package   image(folder)
             *  ( or              |
             *   .class        404error.jpg
             *   files, if
             *   no package
             *   exists.)
             */
            //image = ImageIO.read(
            //      getClass().getResource(
            //              "/image/404error.jpg"));
            image = ImageIO.read(new URL(
                        "http://gagandeepbali.uk.to/" + 
                                "gaganisonline/images/404error.jpg"));
        }
        catch(IOException ioe)
        {
            System.out.println("Unable to fetch image.");
            ioe.printStackTrace();
        }
    }

    /*
     * Make this one customary habbit,
     * of overriding this method, when
     * you extends a JPanel/JComponent,
     * to define it's Preferred Size.
     * Now in this case we want it to be 
     * as big as the Image itself.
     */
    @Override
    public Dimension getPreferredSize()
    {
        return (new Dimension(image.getWidth(), image.getHeight()));
    }

    /*
     * This is where the actual Painting
     * Code for the JPanel/JComponent
     * goes. Here we will draw the image.
     * Here the first line super.paintComponent(...),
     * means we want the JPanel to be drawn the usual 
     * Java way first, then later on we will
     * add our image to it, by writing the other line,
     * g.drawImage(...).
     */
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this);
    }
}

But if you don't want to use inheritance, in your case, then you can simply add your image to the JLabel and then add your components to the JLabel by setting the Layout for the JLabel, as shown in this example and this example.

Community
  • 1
  • 1
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • Hehe, I hope, it clears the doubts one has in mind, regarding the topic. Thankx though for appreciation :-) – nIcE cOw Oct 03 '12 at 14:13
  • 1
    Awesome... Really a wonderful code! it is very useful to me. Now I am reading carefully, I will try in a few moment, I let you know – Gianmarco Oct 03 '12 at 14:25
  • @Gianmarco : now if you wanted to add another JPanel on top of this one, simply make the new JPanel's opaque property to false, so that the image beneath it can be viewed by the user. – nIcE cOw Oct 03 '12 at 14:35
  • Ok, something is working... But I have few problems: 1- I had to use ImageIO.read(new File(etc)) in order to have the image loaded. I can't figure out how to edit my directory structure (i'm using eclipse), I select "new > source folder" but when I set the name as "bin" I get this error: Source folder 'src' in project 'Garby' cannot output to distinct source folder 'bin' Don't know how to fix it. Maybe it's better to re-create all the project, any idea how to do it properly? (is there any standard in java?) 2 - is possible to align bottom right the image? – Gianmarco Oct 03 '12 at 14:46
  • @Gianmarco : [HOW TO ADD IMAGES TO YOUR PROJECT IN ECLIPSE](http://stackoverflow.com/a/9278270/1057230), this answer might can help you in this direction. Don't set the name of the Source Folder as bin, since it is created by default I guess, rather name is something else, when you run your application, the content of the Source Folder will be automatically added to the bin. After running you can check that, those will be inside the bin Folder. – nIcE cOw Oct 03 '12 at 14:49
  • AFA, bottom align right is concern, for that you can put a JPanel to the BorderLayout.PAGE_END location and set it's Layout to `setLayout(new FlowLayout(FlowLayout.RIGHT, 1, 1));` and then add a JLabel with one image on it, that will do :-) – nIcE cOw Oct 03 '12 at 14:53
  • I was wondering if getClass().getResources() works in a static method... eclipse is angry about that, now I moved all my images in the bin directory, but in the main method, and in all the static method, i can't use getClass().getResources().... have I to create 2 different folder for my images? I hope not... – Gianmarco Oct 03 '12 at 15:11
  • I really don't know why you creating static methods, since static keyword used for no reason is not a good option, why cann't your method be `non static/ordinary`. If your intend is to use the methods in other classes, rather pass the reference of the class to them, instead of creating static methods. – nIcE cOw Oct 03 '12 at 15:22
  • I created 3 static class, Database, Console and GUI. Because they are accessible where I want just calling: Database.methodName I do not need references, is a kind of MVC, Core, Database and GUI.. but I found a solution, I call getClass in any Object in my static method. it work well.. the thing I can't solve is how to bottom right position my image. I can't make a label because I need it in the background (and is for this reason that we've override paintComponent). The windows is always maximized. I hope I could explain what i mean, sorry for my bad english, I am italian. – Gianmarco Oct 03 '12 at 15:30
  • Had you seen the example given by me in the links at the end of my answer, you can use a JLabel for this and set the Layout for the JLabel, it can also be used as a holder for the background image. Or else you can use `YourClassName.class.getResource("/image/Space.png")` to use this in your static methods, as used in this [example](http://stackoverflow.com/a/12684641/1057230) :-) – nIcE cOw Oct 03 '12 at 15:34
  • Yes I read the link, but I can't have it working, I prepare the JLabel with the image and put it into the frame, then I put the "main" JPanel also into the frame... not working... I didn't understand very well I think... – Gianmarco Oct 03 '12 at 15:49
  • 1
    By the way. here's my solution, starting from your code: g.drawImage(image, (int) (getSize().getWidth() - image.getWidth()), (int) (getSize().getHeight() - image.getHeight()), this); Thankyou for the help – Gianmarco Oct 03 '12 at 16:07
  • You can have a look at this [example](http://stackoverflow.com/a/11428289/1057230) of mine for better understanding, how to add components to your JLabel – nIcE cOw Oct 03 '12 at 16:14
3

You can use OverlayLayout. It lets you stack components one on each other. Adding an image as the lowest one like this should work:

JPanel backgroundPanel = new JPanel();
backgroundPanel.setLayout(new OverlayLayout(backgroundPanel));

backgroundPanel.add(/* your panel with controls */);
backgroundPanel.add(/* image component */);

Note that your panel with controls should be transparent not to hide the background image. You can achieve this by setting panel.setOpaque(false);

pbetkier
  • 1,657
  • 1
  • 13
  • 10
  • i tried this with two panel containing two label. I could not understand why was visible only the last added and not the first i was also using: add(Component comp, new Integer(depth)); – Gianmarco Oct 03 '12 at 14:24
  • @Gianmarco You need to set opaque property of the panels to false to make them transparent. Thanks for the feedback, I will edit my answer. – pbetkier Oct 03 '12 at 14:31
  • +1 for `OverlayLayout`, heard it for the first time, will try my hands on it soon :-) – nIcE cOw Oct 03 '12 at 16:22
0

You can do something like this:

Image image = new ImageIcon(path);     
JLabel label=new JLabel(image);

I think that might do the job you want, if you want to use a JLabel as background Image.

Anyways, you might want to take a look at the ImageIcon Javadoc aswell.

Fabio
  • 791
  • 1
  • 7
  • 27