Skip to main content

"Transparent" Panel - Mixing Heavyweight and Lightweight Components

November 2, 2009



When overlaying lightweight Swing widgets on top of heavyweight AWT components, it is convenient to group the Swing widgets on a transparent (non-opaque) JPanel so that one can use Swing layout managers and/or Swing utilities on a group of related Swing widgets. For example, all widgets added to the transparent JPanel can be made visible or invisible simultaneously with one setVisible() call on the JPanel. Unfortunately, a lightweight JPanel overlaid on top of a heavyweight AWT component cannot be transparent.

To overcome this problem, one can implement a TransparentPanel as shown below.

public class TransparentPanel extends JPanel {

    /**
     * Default constructor. Sets the layout manager to JPanel's
     * default layout manager: FlowLayout.
     */
    public TransparentPanel() {
        this(new FlowLayout());
    }

    /**
     * Construct panel with input layout manager.
     *
     * @param mgr The layout manager for the extended JPanel.
     */
    public TransparentPanel(LayoutManager mgr) {

        // set layout manager, if any
        super(mgr);

        // set opaque false so that an isOpaque() == false
        super.setOpaque(false);
  
// set mixing cutout -- see AWTUtilitesClass below
AWTUtilitiesClass.setMixingCutoutShape(this,
                                               new Rectangle());
    }

    /**
     * Override setOpaque so that the user cannot change the
     * opacity of this panel, since it is after all suppose to
     * be transparent.
     *
     * @param isOpaque Is this panel opaque?
     */
    @Override
    public void setOpaque(boolean isOpaque) {
        // do not allow this to become opaque because it is
        // transparent after all
    }

}

Note that the constructor of TransparentPanel invokes AWTUtilitiesClass.setMixingCutoutShape(). Invoking AWTUtilitiesClass.setMixingCutoutShape() is necessary to avoid non-rendering of our TransparentPanel which would result in a solid gray (and not transparent!) TransparentPanel.

The AWTUtilitiesClass "mixing cutout" technique is described in Mixing Heavyweight and Lightweight Components, October 2009 by Sharon Zakhour and Anthony Petrov, whose code has been excerpted below:

public class AWTUtilitiesClass {

    private static Method mSetComponentMixing;

    static try {
        Class awtUtilitiesClass =
              Class.forName("com.sun.awt.AWTUtilities");
        Method mSetComponentMixing =
              awtUtilitiesClass.getMethod(
                            "setComponentMixingCutoutShape",
                            Component.class, Shape.class);
              mSetComponentMixing.invoke(null, component, shape);
} catch (Execption ex) {
              ex.printStackTrace();
}

    public static void setMixingCutoutShape(Component c, Shape s)
    {
        if (mSetComponentMixing != null) {
            try {
                mSetComponentMixing.invoke( null, c, s );
            } catch (Exception ex) {
                ex.printStackTrace();
            }
}
    }
}

Real World Example: Mixing Swing and Java WorldWind - Software vs Hardware Acceleration

When developing Java WorldWind applications, it is typical for the developer to overlay a JPanel (which contains Java Swing GUI components) above a WorldWind Java container (which contains the rendered world). The WorldWind Java container is usually (1) a GLJPanel which is a subclass of the lightweight Swing JPanel, or (2) a GLCanvas which is a subclass of the heavyweight AWT Canvas.

If Option 1, GLJPanel, is utilized, then the Java WorldWind developer (a) maintains the ability to overlay transparent Swing components above the world (that is, the GLJPanel). However, when attempting to turn on software acceleration, the developer will often find that doing so (b) creates run time exceptions that are difficult if not impossible to overcome, and (c) the performance gained is inferior to performance gains of hardware acceleration.

If Option 2, GLCanvas, is utilized, then the Java WorldWind developer (a) loses the ability to overlay transparent Swing components above the world (that is, the GLCanvas). However (b) runtime exceptions are not experienced, and (c) the performance gained is superior to software acceleration. Additionally, the TransparentPanel introduced in this article coupled with the "mixing cutout" from A. Petrov's article restores the ability for the Java WorldWind developer to maintain inter-component transparency, thus partially alleviating the problems of (a) and more readily allowing the Java WorldWind developer to combine lightweight Swing overlays (containing "grouped" Swing widgets) with heavyweight hardware acceleration.

Notes:

During development, when using Java Swing components rendered in an overlay above a Java WorldWind layer, a predictable gray flash (flicker) was detected. To alleviate this problem, one can utilize the flag:

[prettify]-Dsun.awt.noerasebackground=true
[/prettify]

If one wishes to override the paint() method of a TransparentPanel subclass such that the subclass uses Java2D to draw a Shape onto the superclass TransparentPanel, then the "mixing cutout" described above can cause the TransparentPanel and anything drawn on it to vanish. To resolve this, instead of passing the empty Shape via new Rectangle() to AWTUtilitiesClass.setMixingCutoutShape(), one should pass the shape of the desired drawing. See Mixing Heavyweight and Lightweight Components, October 2009.

If one wishes to overlay a non-rectangular lightweight component above a heavyweight component, one must bear in mind that Java Shapes (and thus "mixing cutouts") cannot be anti-aliased, so for non-rectangular Swing components, one must smooth the non-aliased "mixing cutouts" using hues or blurring.

Resources

Marina Kamahele has a graduate degree in Computer Science from University of California. Marina is currently a Senior Software engineer at a large software and electronics company.
Related Topics >> GUI   |   Java Tech   |   Programming   |   Swing   |   Featured Article   |   

Comments

Hi Marina, nice post ;) I

Hi Marina, nice post ;) I wrote a similar example for WWJ some time ago: http://theballoonproject.blogspot.com/2009/01/swingannotations-on-wwj.html That shows an example of lightweight component on top of GLCanvas. Cheers.

Nice article, thank you ! But in the end, you mention ...

Nice article, thank you !

But in the end, you mention :
If one wishes to overlay a non-rectangular lightweight component above a heavyweight component, one must bear in mind that Java Shapes (and thus "mixing cutouts") cannot be anti-aliased, so for non-rectangular Swing components, one must smooth the non-aliased "mixing cutouts" using hues or blurring.

I tried to look how to do that, but I am at a dead end. For me, blurring can only be achieved on (Buffered)Images, and cut-out techniques only take a Shape as an argument. How is this supposed to be done, then ?

Thank you for your answer !
Glat'.