Java Tips Weblog

  • Blog Stats

    • 1,185,657 hits
  • Categories

  • Archives

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);

Get The Code

BackgroundPanel.java

Related Reading

Java API: java.awt.Paint

About these ads

57 Responses to “Background Panel”

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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

  6. Anonymous said

    Nice post. It works great and is easy to use. Love it! Thanks for all the effort that went into this.

  7. 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.

  8. Mudassir said

    Loved this one….You solved my biggest trouble !
    Thanks a million rob !

  9. 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.

  10. 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.

  11. William said

    You sir are a true gentleman and a scholar, thank you very much for sharing this class!

  12. 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);
    
    	}
    
    }
    
  13. 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.

  14. 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?

  15. Bruno Pinheiro said

    Worked very well , tanks !!

  16. Sarang said

    Thank you sir, this code made my problem solve in minutes…. thanx a lot…. :)

  17. bohalloran95 said

    You have no idea how much aggravation this has saved me! Thank you!

  18. 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);
    }
    
  19. psycho said

    How I can use it with Netbeans in a jForm?

  20. 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?

  21. This is awesome – thanks Rob!

  22. 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.

  23. 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!

  24. Josh said

    Thanks Rob! This works perfectly!

  25. Sam said

    Awesome!! Works perfectly :D Thanks for sharing

  26. bansidhe said

    Yowza! So easy, and works perfectly as far as I can tell! I love it. Thanks!

  27. Oscar Hernández said

    Thank you very much Mr. Camick, this did the trick for me.
    However, at first it “didnt work” as some people here have mentioned but after a bit of fiddling through the code I found out that it is because if you add more elements to the elements that are put inside the BackgroundPanel you have to set those to be transparent manually. Dont know if this is something that can be fixed in the actual class code though.

    Otherwise I really like it, thanks!

    • Rob Camick said

      That was a design decision that I made. I decided that only components directly added to the panel should be automatically made non-opaque. If you want everything that you add to the panel they you could customize the current code to do a recursive loop through all the components found on the panel being added.

  28. Anonymous said

    Thanks Rob. This works awesome.

  29. Anonymous said

    Thanks rob. My only question is when I add things to the BackgroundPanel, they are added below the image rather than on top of it… what can I do to fix this?

    • Rob Camick said

      The whole point of the BackgroundPanel is to have components painted on top of the image. I don’t know what you could be doing wrong. I suggest you create a SSCCE and email it to me via the “Contact Us” page. I would guess that when you attempt to create the SSCCE you will find the problem.

  30. Deeps said

    Hi, if you set an image over a JLabel and set it in contentpane of JFrame… the how would you add other components to the same frame?

  31. Bruce said

    Your example was easy to understand, quickly educated me on what I wanted to know, and was simple to test and adapt. Thanks !

  32. Ben said

    Hi, is there any way to make this work for an animated gif?

    • Rob Camick said

      Not that I know of. You would need to use the first suggestion which is to just use the JLabel as the background and then set an appropriate layout manager.

  33. KennyMc said

    Hi,

    It doesnt seem to be working for me. I get an error saying ‘BackgroundPanel cannot be resolved to a type’

    Here are my imports –

    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.sql.*;
    import java.text.*;
    import java.util.*;
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.table.*;
    import javax.xml.parsers.*;
    import org.apache.xml.serialize.OutputFormat;
    import org.apache.xml.serialize.XMLSerializer;
    import org.w3c.dom.Document;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import java.io.*;

    • Rob Camick said

      BackgroundPanel extends JPanel. You can use it anywhere you use a JPanel. Since you import javax.swing.*, it should work. The problem is with your statement where you use the BackgroundPanel.

      • KennyMc said

        Hi,

        Thanks for your quick response, I have now reduced the code to the following and still see the same error

        public class NewTest1 {

        BackgroungPanel bgPanel;

        /**
        * @param args
        */
        public static void main(String[] args) {
        // TODO Auto-generated method stub

        }

        }

        Then when I hover over it, I dont get the option to import anything, simply just Create new class, Create Interface etc.

        I am using eclipse.

        Thanks

      • Rob Camick said

        I don’t use an IDE to develop but basically you need to make sure the BackgroundPanel class is in a directory that is defined in the classpath that Eclipse uses. Maybe you need to add a package statement? Check out the source of other files that you create to see what directory they are defined in. This is an issue with your IDE, not the class so I can’t help.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 91 other followers

%d bloggers like this: