Most Read This Week
By: Brian Maso
Oct. 1, 1997 12:00 AM
I want to start this column by pointing out that Netscape Inc. has announced support for Java 1.1. This is a significant event for us Java developers because I think it means the era of Java 1.0 is coming to an end. Those of you who are not yet familiar with the new features and enhancements of Java 1.1, get cracking! Go to JavaSoft's web site to see what's new.
Java 1.1 has made a large number of additions to the AWT. This is (arguably) the most changed package in Java 1.1 with respect to Java 1.0. Changes include the complete re-engineering of the event model, new and improved Component classes such as the ScrollPane and (insert drum roll) Lightweight Components.
Lightweight Components are a new addition to the AWT. A Lightweight Component is a particular class of visual Component, so it can be used just like any other Component (i.e., Canvas, List, Choice, etc.). Lightweight Components have two distinctions over other Component classes. (Note: the term Heavyweight Component' is generally used to mean any Component that is not Lightweight.) Lightweight Components are transparent and you have control over z-ordering.
Transparency means that you can see through' Lightweight Components. For example, let's say you've created a Panel-derived container that displays a background image. A Lightweight Component placed in the center of this panel will not obstruct the background image. Instead, the background image will show through the Lightweight child Component. Normal, Heavyweight Components won't do this. Try placing a Canvas in the middle of your background image Panel and you'll see the bounding rectangle of the Canvas clips the background image.
Control over z-ordering is something that's been missing from the AWT from the beginning. Z-ordering refers to how sibling Components are visually placed on top of each other. A Component with higher z-order appears on top' of sibling Components that overlap it. In Java 1.0, z-ordering is not something you can control. Different AWT implementations (Win32, Motif, Mac, etc.) arbitrarily set the z-ordering of sibling Components and you really have no control over that. Lightweight Components, on the other hand, define a specific policy for z-ordering of siblings that is always reproduced the same way no matter what implementation of the AWT you are using.
Lightweight Components have the strange distinction of having no native peer in any windowing platforms. In case you don't know exactly how it works, let's review Components and peers in the AWT. Each Component, be it a Canvas, List, Choice, Scrollbar, Panel or any object inheriting from the Component class, has a peer object. Each implementation of the AWT Toolkit implements its own set of peers. For example, the Windows 32-bit O/S's (Windows 95 or Windows NT) implement the Windows toolkit in a package named sun.awt.win32.*. A quick perusal of this package shows these classes have been implemented to provide access to the Win32 windowing API (through native methods we can assume): MComponentPeer, MCanvasPeer, MFramePeer, etc. Each of these peer classes implements calls to the Windows operating system for generic Java methods. So, the Canvas class' setBackgroundColor() method actually calls its MCanvasPeer object's setBackgroundColor() method, which in turn makes a native call to the Windows API to physically set the background color of the Component in the Windows system.
I think of Lightweight Components as being the first truly platform-independent components in Java. That is, they are displayed the same in all windowing systems, always act the same and are completely de-coupled from the windowing platform a particular VM happens to be using. Compare that to the heavyweight Components of Java 1.0; these heavyweight Components appear differently and, in some cases, even have different behaviors based on the windowing platform that happens to be in use.
On a Windows 95 system a TextField looks completely different than it does on a Mac system. That's an example of appearance differences between different AWT implementations. Java is rife with these. Basically, the only heavyweight Components that do look the same on different windowing systems are the Canvas and Panel Components. That's because Canvases and Panels really don't have any particular look. They are displayed as blank screen rectangles, which is pretty easy to do the same in all the different windowing systems.
An example of behavioral differences between different windowing platforms is the behavior of Scrollbars in Win32 systems vs. Motif systems. The maximum extents and current values of Scrollbars have different meanings in these two types of windowing systems, which makes coding them quite difficult. (Note that this problem has been fixed as of Java 1.1.3, but only through the use of hidden compensator code added to implementations of Win32 AWT toolkits.) While there are fewer behavioral discrepancies between different windowing platforms than there are visual differences, the fact that there are any differences at all is a failure of Java. Java should always be platform-independent. Differences in look or behavior, no matter how you sugar-coat them, are still platform dependencies. Anyway (dismount from high-horse), Lightweight Components get rid of these differences altogether.
(If I may toot my own horn for a moment, I'd like to point out that I outlined a technique very similar to that used for Lightweight Components in my first book, "The Java Networking and AWT API SuperBible" even before the release of Java 1.0.2. In the book, I called them 'peerless Components', but the technique and implementation is very similar to Java 1.1's Lightweight Components.)
The Java class java.awt.Lightweight is the base class for all Lightweight Components. It is derived from the Component class but it is not abstract. The Lightweight class is part of a delegation model for Component painting and event handling. In Java 1.0, the Container class method paint() is not overriden. In Java 1.1, the method Container.paint() has been overriden from Component.paint(), as shown in Listing 1.
So you can see that for each Lightweight Component within a Container, the Container explicitly calls the Lightweight's paint() method using a new Graphics object whose clipping rectangle is set to the bounding rectangle of the child Component. That is, the Container delegates painting of the rectangle covered by the Lightweight Component.
A couple of important points have to be stressed here. First, if you override Container.paint() in a derived class, you must make sure to call super.paint() also, or else the delegation of painting to Lightweight children won't happen. I mentioned earlier in this column the case where you construct a Panel-derived class that displays a background image. The proper implementation of the paint() method for this example would look like Listing 2.
The other important point here is that Lightweight.update() is not called as part of the process. Instead, Container class code calls Lightweight.paint() directly. This means that neither the foreground color nor the font is set in the Graphics object that is passed to Lightweight.paint(). You must set these two values directly, as seen in Listing 3.
Also, Lightweight Components do not automatically get erased with the background color like heavyweight Components do. In fact, this is what gives Lightweights their transparent property.
From the pseudo-code for the Container class's implementation of paint(), you can also see how z-ordering is handled in Java 1.1 for Lightweight Components. Lightweight Components are painted in the order they are added to a Container. The first Lightweights added to a Container have the lowest z-order. The Lightweights added last have the highest z-order.
Note that z-ordering is not preserved between Lightweight and heavyweight Components. You cannot control the z-ordering of sibling heavyweights. However, heavyweights always have a higher z-order than sibling Lightweights, no matter in what order the siblings are added to the parent Container.
Java 1.1's Container class implementation delegates handling of other events to Lightweight Components if the event happens within the bounding rectangle of the Lightweight Component. This is done similarly to how painting delegation occurs. (The implementation of Java 1.1's new event model is what implements this event handling delegation. The code is, unfortunately, too long and complex to cover in this column, but take my world for it that Lightweight.dispatchEvent() is called at appropriate times explicitly by the Container class.)
Reader Feedback: Page 1 of 1
Subscribe to the World's Most Powerful Newsletters
Today's Top Reads