Mixing Heavyweight and Lightweight Components (original) (raw)

By Sharon Zakhour and Anthony Petrov
Published April 2010

Historically, in the Java language, mixing heavyweight and lightweight components in the same container has been problematic. However, as of the JDK 6 Update 12 and JDK 7 build 19 releases, mixing heavyweight and lightweight components is easy to accomplish. This article explains some details you might need to know.

A Bit of History

There are two kinds of graphics components in the Java programming language: heavyweight and lightweight. A heavyweight component is associated with its own native screen resource (commonly known as a peer). Components from the java.awt package, such as Button and Label, are heavyweight components. Third-party heavyweight components, such as the following, are also becoming increasingly popular:

A lightweight component has no native screen resource of its own, so it is "lighter." A lightweight component relies on the screen resource from an ancestor in the containment hierarchy, possibly the underlying Frame object. Components from the javax.swing package, such as JButton and JLabel, are lightweight components.

In the past, mixing heavyweight and lightweight components in the same graphical user interface (GUI) caused problems when those components overlapped one another. For example, the following screen capture shows a menu bar that contains both a lightweight menu and a heavyweight menu. The frame contains a heavyweight button. The heavyweight menu behaves as expected: When selected, the heavyweight menu is displayed on top of the button. But, when the lightweight menu is displayed, the heavyweight button takes precedence where they overlap.

MenuMixingBroken

In this next screen capture, the lightweight button behaves properly, but the heavyweight button overlaps the lightweight scrollbar.

ScrollPaneMixingBroken

In this final screen capture, there are two overlapping JInternalFrame instances, one frame containing a heavyweight button and the other frame containing a lightweight button. Though Internal Frame 2 overlaps Internal Frame 1, the heavweight button in Frame 1 appears on top.

InternalFrameMixingBroken

Component Mixing Just Works

As of the JDK 6 Update 12 and JDK 7 build 19 releases, it is now possible to seamlessly mix heavyweight and lightweight components within the same container. The following screen captures show the same three examples, run under the JDK 7 release, with no changes to the code. In each case, it just works.

ScrollPaneMixingFixed

MenuMixingFixed

InternalFrameMixingFixed

Requirements

The capability to mix heavyweight and lightweight components works by default, if you are using the JDK 6 Update 12 release or the JDK 7 build 19 release. In most cases, this functionality will just work, but there are a few situations that might affect your code:

   /**      * Sets a 'mixing-cutout' shape for the given component.      *      * By default a lightweight component is treated as an opaque rectangle for      * the purposes of the Heavyweight/Lightweight Components Mixing feature.      * This method enables developers to set an arbitrary shape to be cut out      * from heavyweight components positioned underneath the lightweight      * component in the z-order.      *      * The {@code shape} argument may have the following values:      *      * - {@code null} - reverts the default cutout shape (the rectangle equal      * to the component's {@code getBounds()})      * - empty-shape - does not cut out anything from heavyweight      * components. This makes the given lightweight component effectively      * transparent. Note that descendants of the lightweight component still      * affect the shapes of heavyweight components.  An example of an      * empty-shape is {@code new Rectangle()}.      * - non-empty-shape - the given shape will be cut out from      * heavyweight components.      *      * The most common example when the 'mixing-cutout' shape is needed is a      * glass pane component. The {@link JRootPane#setGlassPane()} method      * automatically sets the empty-shape as the 'mixing-cutout' shape      * for the given glass pane component.  If a developer needs some other      * 'mixing-cutout' shape for the glass pane (which is rare), this must be      * changed manually after installing the glass pane to the root pane.      *      * Note that the 'mixing-cutout' shape neither affects painting, nor the      * mouse events handling for the given component. It is used exclusively      * for the purposes of the Heavyweight/Lightweight Components Mixing      * feature.      *      * @param component the component that needs non-default      * 'mixing-cutout' shape      * @param shape the new 'mixing-cutout' shape      * @throws NullPointerException if the component argument is {@code null}      */     public static void setComponentMixingCutoutShape(Component component,         Shape shape);

**Note:**The com.sun.awt API is not part of an officially supported API and appears as an implementation detail. The API is only meant for limited use outside of the core platform. It might change drastically between update releases, and it might even be removed or moved to another package or class. Therefore, this method should be used only through the Java reflection mechanism. For example:

try {     Class awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities");     Method mSetComponentMixing = awtUtilitiesClass.getMethod("setComponentMixingCutoutShape",                     Component.class, Shape.class);     mSetComponentMixing.invoke(null, component, shape); } catch (NoSuchMethodException ex) {     ex.printStackTrace(); } catch (SecurityException ex) {     ex.printStackTrace(); } catch (ClassNotFoundException ex) {     ex.printStackTrace(); } catch (IllegalAccessException ex) {     ex.printStackTrace(); } catch (IllegalArgumentException ex) {     ex.printStackTrace(); } catch (InvocationTargetException ex) {     ex.printStackTrace(); }

Limitations

A few situations are not supported:

Some applications have already implemented a mechanism to mix lightweight and heavyweight components. In this situation, this built-in mixing feature might cause problems. The mixing feature can be turned off by using the private sun.awt.disableMixing system property. For more information, see bugs 6788954 and 6851271. By default, the mixing feature is enabled.

Demo

Here is a basic NetBeans calculator example you might find useful, Calc.zip. In this example, the buttons for the numbers and mathematical symbols are heavyweight, and the menu is lightweight. If you have the correct version of the JDK installed, they will interact correctly.

Calculator CalculatorMixing

Otherwise, if you are using an older version of the Java platform, the buttons will overlap the pop-up menus.

Click here to run the calculator example.

Sharon Zakhour is a staff technical writer at Oracle. Her responsibilities include the Java Tutorials and the tutorials portal. She enjoys travel and plans to do more after her two teenaged daughters flee the nest.

Anthony Petrov is a software engineer in the AWT team. His areas of responsibility include top-level windows, splash screen, and other.