Background Panel
Posted by Rob Camick on October 12, 2008
Many people want to know how to add a backgound image to a frame. The easiest way to do this is to add an image to a JLabel and then add the label to the frame. Is there a better way? Well, the answer depends on your requirements.
The code for this easy approach would be something like:
JLabel contentPane = new JLabel();
contentPane.setIcon( backgroundImage );
contentPane.setLayout( new BorderLayout() );
frame.setContentPane( contentPane );
Why does this work? Well, remember that all Swing components extend Container so you can add child components to them. However, by default, a JLabel uses a null layout so the components don’t appear. By using a BorderLayout the label can now function like a panel and be used as a content pane.
However, this approach has drawbacks, mostly because a label aways paints the image at it actual size. So in reality it would probably only be used on fixed size windows where the size of the window is determined by the size of the image.
In most other cases we need a more flexible approach, so we need a more flexible component. Introducing, BackgroundPanel, an extension of JPanel that provides some custom painting support for the drawing of images. The basic support provided by this class allows the images to be painted in one of 3 styles:
- scaled image (the default)
- tiled images
- actual sized image - the position of the image is controlled by specifying the horizontal and vertical alignment (center alignment is the default)
In addition to drawing images, this component can also be used to paint backgrounds that are not a solid colour. The Java API conveniently provides a Paint interface. A new setPaint(…) method was added to specify a Paint object to be used by the custom painting code. The Paint object can be used without an image. When both an image and a Paint object are used, the order of painting will be:
- paint the background
- paint using the Paint object
- draw the image
Also, the add(…) methods have been overridden to make each component added to the panel non-opaque. After all, if you are going to all the trouble to create a fancy background you dont want your opaque panel to block the custom painting. For components that use a renderer the renderer will also need to be transparent. For example, on a JTable, you can use the following to set the alpha value of the Color to 0, which results in a transparent background colour:
table.setBackground( new Color(0, 0, 0, 0) );
Following is the the code used to create the panel displayed in the attached image:
BackgroundPanel panel =
new BackgroundPanel(duke, BackgroundPanel.ACTUAL, 1.0f, 0.5f);
GradientPaint paint =
new GradientPaint(0, 0, Color.BLUE, 600, 0, Color.RED);
panel.setPaint(paint);

Arasdasd said
THIS DID NOT WORK
WASTE OF TIME
Rob Camick said
Not a very helpfull comment. Of course it works or I wouldn’t take the time to write the blog entry or post the code. It may not work the way you want it to or expect it to, but that does not make it wrong, only different. If you have a specific problem you can always sent your “demo” code by using the “Contact Us” link.
Greg Blass said
Great post here. You would not believe how many other links I looked at before I was able to use the simple 4 lines of code you posted to add a background image to a JFrame. Thanks Rob.
Rob Camick said
Thanks for the feedback. Glad your searching lead you to an answer.
Eli said
Worked for me =)
BackgroundPanel bgPanel = new BackgroundPanel(img, BackgroundPanel.SCALED, 0.0f, 0.0f);
SCALED is so awesome, thank you! Fits the image, however you resize the frame.
Garratt said
Hey Rob, This seems like it would be perfect for what I’m trying to achieve (scaled image) but I’m having trouble. I’m wondering why use ‘Image’. From what I can tell that means I need to make another class that extends Image and defines its methods. Typically for images I use ImageIcon as it can be easily instantiated but ‘Image’ is an abstract class and therefore cannot be instantiated.
JLabel.setIcon(new ImageIcon("resources/img.png");Not sure how to make this class work from the example given.Can you please explain how I create and use the default method for the class?
Rob Camick said
There is no need to use an ImageIcon to read in an Image. You can use ImageIO to read the Image. But if you really want to use an ImageIcon you can use the getImage() method to get the actual Image.
James Wars said
The BackgroundPanel does not show the image when multiples panels and a frame are used. I have a structure that starts at the top level with a JFrame ‘frame1′ then a JPanel ‘MainPanel’—(CardLayout structure) and inside the MainPanel, i have another JPanel ‘StudentPanel’ that shows yet another small sized JPanel ‘ImagePanel’ that finally add as a component the BackgroundPanel and sets it’s BorderLayout.CENTER?
Does this mean i have to repaint and revalidate every single one of these panels?
Rob Camick said
You don’t add the BackgroundPane to your ImagePanel
You add the Image to the BackgroundPanel. Then you can add other components to the BackgroundPanel if your wish.
If you need more help then post a proper SSCCE that demonstrates the problem. If you don’t know what a SSCCE is then search the web.
Rob
Anonymous said
Nice post. It works great and is easy to use. Love it! Thanks for all the effort that went into this.
Rob Camick said
Glad you found it easy to use.
gadget00 said
I’ve been trying to use this on a JDesktopPane, which is on top of a JFrame but so far I haven’t been able to roll it. Will it work?
Rob Camick said
I don’t think you can use this panel directly on a JDesktopPane because it is designed to drag components around the pane. However, you should be able to override the paintComponent() method of your desktop panel to use the painting code found in this class.
Mudassir said
Loved this one….You solved my biggest trouble !
Thanks a million rob !
Rob Camick said
Glad your problems are solved.
Ayaaz said
Hey but there is one small glitch, I don’t know if that’s from my side or not… Well,the thing is when I run my code, my frame is visible with out the background image, & until I re size/minimize/maximize the frame, background doesn’t show up, why is it so ?
Rob Camick said
If a component doesn’t paint until you resize the frame that is usually an indication that you added the component to the frame AFTER the frame was made visible. All components should be added to the frame BEFORE you make the frame visible.
Ayaaz said
One more thing is….I think I am unable to use it on other lay-outs, except for the default layout of java swing, can u put some light on it please ?….Thanks :)
Rob Camick said
I updated the source code to provide a default “preferred size” equal to the size of the image being used.
Richard said
This was a lifesaver and easy to implement! Like it so much that this is my first posting to code samples…
Thank you!!!
Richard
Richard said
Also – for folks new to Java (like me)… download the ‘BackgroundPanel.java’ file and drag it into the package that contains your JFrame. There’s probably other ways, but that worked for me.
William said
You sir are a true gentleman and a scholar, thank you very much for sharing this class!
Rob Camick said
Thanks for the support.
Paul said
Some working code…
public class Main { public static void main(String[] args) { JFrame frame = new JFrame("Test"); BufferedImage img = null; try { File f = new File("./images/grid30x30_light.png"); img = ImageIO.read(f); System.out.println("File " + f.toString()); } catch (Exception e) { System.out.println("Cannot read file: " + e); } BackgroundPanel background = new BackgroundPanel(img, BackgroundPanel.TILED, 0.50f, 0.5f); frame.setContentPane(background); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 100); frame.setVisible(true); } }Nikos said
Thank you,
this saved me a lot of time..
In my case I wanted to add a JScrollPane with a JtextPane on a “tiled” BackgroundPanel ,but I didn’t want the background of the JTextPane to change so I just had to erase the “if” block in the “makeComponentTransparent” and everything worked fine.
Rob Camick said
Glad it saved time. Instead of customizing the code you could have used the setTransparentAdd(…) method. Set it to false, add the component and then reset to true.
sunil shahi said
Thank you very much however I need 1 more help from you.. I used Paul’s code above as a demo to understand. Of course it works but I need to give the whole path of the image like “C:\\Users\\Owner\\Documents\\NetBeansProjects\\FetchMail\\src\\myPackage\\BackGround.PNG” to make it work. if I do ./myPackage/BackGround.PNG it doesnot work. Can you help me where I am doing the mistake?
Bruno Pinheiro said
Worked very well , tanks !!
Sarang said
Thank you sir, this code made my problem solve in minutes…. thanx a lot…. :)
bohalloran95 said
You have no idea how much aggravation this has saved me! Thank you!
Anarcho-Willi said
This class was indeed a great time saver for me as well. I added two different types of displaying the background images (horizontally and vertically scaled):
/* * Custom painting code for drawing a SCALED_HORIZONTAL image as the * background */ private void drawScaledHorizontal(Graphics g) { Dimension d = getSize(); Insets insets = getInsets(); int height = d.height - insets.top - insets.bottom; float ratio = 1.0f * d.width / image.getWidth(null); int imgHeight = (int) (image.getHeight(null) * ratio); float y = (height - imgHeight) * alignmentY; g.drawImage(image, 0, (int) y + insets.top, d.width, imgHeight, null); } /* * Custom painting code for drawing a SCALED_VERTICAL image as the * background */ private void drawScaledVertical(Graphics g) { Dimension d = getSize(); Insets insets = getInsets(); int width = d.width - insets.left - insets.right; float ratio = 1.0f * d.height / image.getHeight(null); int imgWidth = (int) (image.getWidth(null) * ratio); float x = (width - imgWidth) * alignmentX; g.drawImage(image, (int) x + insets.left, 0, imgWidth, d.height, null); }psycho said
How I can use it with Netbeans in a jForm?
red said
Thanks for this great component! I think that there’s a little problem. I’ve a BagrkoundPanel p1 which renders correctly his image. p1 has a smaller child JPanel which should render a background color: in fact it doesn’t! I think that the problem is related to paintComponent… maybe at the end of method, a revalidate for all children must be invoked?
red said
I think I’ve found a solution… there’s a property transaprentAdd which solves perfectly my problem! Great work!
Martijn Verburg (@karianna) said
This is awesome – thanks Rob!
Rob Camick said
Thanks for the feedback.
K said
When I tried using this, I noticed it gobbling up all of my CPU and discovered that the repaint() at the end of paint_component() puts it into an infinite loop. Commenting out that call fixed the problem and everything still works fine.
Rob Camick said
This class does not use the repaint() method in the paintComponent() method. You must have modified your version. Maybe try downloading the code again to make sure you have the original version.
ADreaming said
Second semester CSCI minor here. I’m using this for my final homework assignment, and I love it! Thanks for this awesome code!
Josh said
Thanks Rob! This works perfectly!
Sam said
Awesome!! Works perfectly :D Thanks for sharing