Backgrounds With Transparency
Posted by Rob Camick on May 31, 2009
Swing components allow you to change the background color of a component simply by using the setBackground() method. It is also possible to use a Color created with an “alpha” value. The alpha value defines the transparency of a Color. Unfortunately, once you start using alpha values in your background color you may encounter some undesireable painting artifacts.
To understand the problem we need to look at the setOpaque() method of Swing components. When the opaque value is:
- true – The component agrees to paint all of the pixels contained within its rectangular bounds. This is done by painting the background before doing the custom painting of the component.
- false – The component makes no guarantees about painting all the pixels within its rectangular bounds. Therefore the RepaintManager needs to do extra work. It needs to find an opaque ancestor of the component. Once it does, it then repaints the ancestor and all its children to make sure the rectangular bounds of the component is completely repainted.
Either way you are assured that all the pixels in the bounds of the component are painted every time the component is repainted.
So what happens when you introduce an alpha value in the background color of the component? Well, if the opaque value is
- true – all the pixels are repainted, but because they are now transparent, you may see unexpected painting artifacts
- false – the ancestor component and children are painted, but the components background is not painted so you lose the transparency effect.
Either way you don’t get the result you expect.
In the image below, the checkboxes are transparent and the panel uses a transparent background color. Everytime the mouse moves over a checkbox the transparency is reapplied resulting in an increasingly less transparent and darker background color:

The solution is to make sure the ancestor of the component is painted before the components background is painted. This is done in two steps:
- first, the component is made non-opaque, by using setOpaque(false)
- next, you add custom painting to the component to paint its background, by overriding the paintComponent() method. Note, when the alpha value is 0, then you can skip this step since the color is completely transparent so there is nothing to paint.
An example of applying the above two steps to a JPanel is shown below:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false);
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);
Eventually you may get tired of continually extending components to do this type of custom painting. Using the AlphaContainer class provides a reasonably easy workaround. It works by wrapping the transparent component and by doing the painting of the background using the components background color. The AlphaContainer will also manage the opaque property of the component. To use the AlphaContainer, the above code can be changed to:
JPanel panel = new JPanel();
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add( new AlphaContainer(panel));
Next time you notice painting artifacts when using a transparent background Color try one of the above suggestions.
Try The Demo
– Using Java™ Web Start (JRE 6 required)
Get The Code
Related Reading
Painting in AWT and Swing – Additional Paint Properties
Java API: java.awt.Color