When it comes to discussing Java user interfaces, the Swing component set gets all the press. But there's more to GUIs than Swing. Just like with earlier releases of the Java platform, Swing is built on top of the Abstract Window Toolkit (AWT).
What does it mean by "on top of"? Nothing happens in Swing without underlying support in AWT. For instance, the original version of AWT had what is called peered components; when you created an AWT Button component, it created a native component. On a Microsoft Windows machines, it would create a Windows button component, and on a Solaris system, it would create a Motif button. Ten years ago, when the Java language was first introduced, native components seemed like the way to go.
Version 1.1 of the Java platform changed things. It added the ability to create peerless or lightweight components. Prior to these changes, Swing couldn't exist; the way to create a custom component was to subclass Canvas, which created a component native to the platform.
But I digress. This month's tip isn't about the origins of Swing or the Java language, it's about how AWT advanced with the 5.0 release. While Swing is typically the most visible change, it certainly isn't the only one. On to the AWT enhancements.
Two new classes added to the Java 5.0 platform are PointerInfo and MouseInfo. These classes help you locate the mouse on the
desktop. Starting with the MouseInfo class, you get two static
methods:
int getNumberOfButtons()tells you how many buttons are on your mouse. Depending on the number of mouse buttons, you may want to configure the available operations differently, as shown in Listing 1:
Listing 1. Counting mouse buttonspublic class Mouse { public static void main(String args[]) { int count = MouseInfo.getNumberOfButtons(); System.out.println("Mouse buttons = " + count); } }
-
PointerInfo getPointerInfo()returns aPointerInfoobject.
The PointerInfo object returned has its own set of two
methods:
GraphicsDevice getDevice()reports the device where the mouse is located, the actualGraphicsDeviceobject. On a system with multiple screens, call this method and get the associatedGraphicsDeviceobject, specific to the mouse location.Point getLocation()gets the physical location of the mouse on screen, as shown in Listing 2:
Listing 2. Getting mouse positionimport java.awt.*; import java.awt.event.*; import javax.swing.*; public class Pos { public static void main(String args[]) { Runnable runnable = new Runnable() { public void run() { JFrame frame = new JFrame("Mouse Position"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel(); label.setHorizontalAlignment(JLabel.CENTER); MouseMotionListener mouseMotionListener = new MouseMotionListener() { public void mouseDragged(MouseEvent e) { showMousePos(e); } public void mouseMoved(MouseEvent e) { showMousePos(e); } private void showMousePos(MouseEvent e) { JLabel src = (JLabel)e.getComponent(); PointerInfo pointerInfo = MouseInfo.getPointerInfo(); Point point = pointerInfo.getLocation(); src.setText(point.toString()); } }; label.addMouseMotionListener(mouseMotionListener); frame.add(label, BorderLayout.CENTER); frame.setSize(300, 300); frame.setVisible(true); } }; EventQueue.invokeLater(runnable); } }
Figure 1 shows this code in action. Moving the mouse over the window changes the coordinate position.
Figure 1. Getting mouse position
The Component class also has a getMousePosition() method that returns
a Point object. The Point returned by
getMousePosition() is the mouse
position based off the component's coordinate space. Calling the
getLocation() method of PointerInfo
works in the coordinate space for the whole graphics device (that is, the screen)
for a single screened system.
If you aren't familiar with the java.awt.Robot class, the Robot class
allows you to move the mouse position. The class has been around
since the 1.3 timeframe and includes an appropriately named mouseMove()
method that has arguments for x and y coordinates. So now, not
only can you move the mouse, but you can discover its position, too.
The concept of z-order describes a third dimension in which to place components and their windows. x and y positioning define the horizontal and vertical positions, respectively, with (0, 0) at the top-left corner of the screen. Adding z-order into the mix allows you to control how components are drawn on top of each other.
At the container level, you get two new methods,
setComponentZOrder(Component c, int layer) and
getComponentZOrder(Component c). The layer passed into the
setComponentZOrder() method starts with 0 as the highest layer,
drawn last, on top of everything else, with increasing numbers
under that.
To demonstrate, the program in Listing 3 creates three
components and places them one on top of another. Working with
z-order involves several steps. First, you need to disable the
layout manager for the container: setLayout(null). If you don't,
and add components with the z-order set, it won't matter as there
will be no overlapping of components. Of course, if you are using a custom layout manager
that overlaps components, that works, too.
Next, you add the components
to the container, without any layout constraints. You then set the z-order
by calling setComponentZOrder() for each component in
the container. As an additional step, for the overlapping
components to draw correctly, the container containing the
overlapping components must have their optimized drawing disabled,
by having their isOptimizedDrawingEnabled() method return false.
This last bit is done by creating a JPanel subclass, as there is
no setOptimizedDrawingEnabled() method.
Listing 3. z-order and AlwaysOnTop
import java.awt.*;
import javax.swing.*;
public class Zs {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
public void run() {
JFrame frame = new JFrame("Z-Ordering");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton top = new JButton("Top");
JButton middle = new JButton("Middle");
JButton bottom = new JButton("Bottom");
int x=25;
int y=75;
int width=100;
int height=50;
int overlap = 25;
int widthDelta = width - overlap;
int heightDelta = height - overlap;
top.setBounds(x, y, width, height);
middle.setBounds(x + widthDelta, y - heightDelta,
width, height);
bottom.setBounds(x + (widthDelta) * 2, y - (heightDelta) * 2,
width, height);
JPanel contentPane = new JPanel() {
public boolean isOptimizedDrawingEnabled() {
return false;
}
};
contentPane.setLayout(null);
contentPane.add(top);
contentPane.add(middle);
contentPane.add(bottom);
contentPane.setComponentZOrder(top, 0);
contentPane.setComponentZOrder(middle, 1);
contentPane.setComponentZOrder(bottom, 2);
frame.setContentPane(contentPane);
frame.setSize(300, 200);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runnable);
}
}
|
Figure 2 shows the results of the code in Listing 3.
Figure 2. z-order
Not only can you control the z-order for individual components
within a container, but you can also manage z-order of windows,
or at least say which one should go on top. Sure, you can call
the toFront() method to make a particular window move to the front,
but now with the Java 5.0 platform, you have the new setAlwaysOnTop() method
of the Window class.
When a window has its alwaysOnTop property set to true, it
will always appear on top of other windows. The other windows
can still have their components selected, but those windows
with alwaysOnTop set to false (the default setting) will remain
in the background.
Listing 4 demonstrates this behavior:
Listing 4. z-order and AlwaysOnTop
import java.awt.*;
import javax.swing.*;
public class Top {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
public void run() {
JFrame frame = new JFrame("Topper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JDialog one = new JDialog(frame, "One");
one.add(new JButton("One"), BorderLayout.CENTER);
one.setSize(100, 100);
one.setLocation(25, 25);
one.setVisible(true);
JDialog two = new JDialog(frame, "Two");
two.add(new JButton("Two"), BorderLayout.CENTER);
two.setSize(100, 100);
two.setLocation(50, 50);
two.setVisible(true);
JDialog three = new JDialog(frame, "Three");
three.add(new JButton("Three"), BorderLayout.CENTER);
three.setSize(100, 100);
three.setLocation(75, 75);
three.setVisible(true);
two.setAlwaysOnTop(true);
frame.setSize(300, 200);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runnable);
}
}
|
Figure 3 shows the results of Listing 4.
Figure 3. Layering windows
Untrusted applications need an AWTPermission in their policy file with a target name of
setWindowAlwaysOnTop, which prevents malicious users from overriding
the whole desktop, making it appear real while the underlying application fishes for information.
Only one active window should have the alwaysOnTop property to
true. If multiple windows are set to true, behavior is undefined and
likely to be platform-specific.
- Read the complete Taming Tiger series.
- Download J2SE 5.0 from the Sun Developer Network.
- The article "2D animation with image-based paths" (developerWorks, January 2004) by Barry A. Feigenbaum and Tom Brunet helps take the heavy coding out of fixed-object animation.
- Read the
PointerInfoclass Javadoc. - Read the
MouseInfoclass Javadoc. - Read the
Containerclass Javadoc. - Sun's J2SE 5.0 documentation discusses AWT enhancements.
- To learn more about Java programming, visit the
developerWorks Java zone. You'll find technical
documentation, how-to articles, education, downloads, product information, and more.
- Visit the New to Java technology site for the latest resources to help you get started with the Java language.
- Get involved in the developerWorks community by participating in
developerWorks blogs.
- Browse for books on these and other technical topics.

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are The Definitive Guide to Java Swing, Third Edition (Apress, June 2005) and Mastering Java 2, J2SE 1.4 (Sybex, April 2002)



