Core Java Technologies Tech Tips Tips, Techniques, and Sample Code Welcome to the Core Java Technologies Tech Tips for January 18, 2005. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE). This issue covers: * Let There Be Z-Order * Customizing Window Adornments These tips were developed using Java 2 Platform Standard Edition Development Kit 5.0 (JDK 5.0). You can download JDK 5.0 at http://java.sun.com/j2se/1.5.0/download.jsp. This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc. (http://www.jzventures.com). You can view this issue of the Tech Tips on the Web at http://java.sun.com/developer/JDCTechTips/2005/tt0118.html See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms. For more Java technology content, visit these sites: java.sun.com - The latest Java platform releases, tutorials, and newsletters. java.net - A web forum for collaborating and building solutions together. java.com - The marketplace for Java technology, applications and services. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LET THERE BE Z-ORDER Before the introduction of the Swing component set, the primary means of user-interface programming in the Java Platform was provided by the Abstract Window Toolkit (AWT). The Swing component set is built on top of AWT, and the AWT layout managers and events are often used when using Swing. J2SE 5.0 adds a number of enhancements and makes a number of bug fixes to AWT. One of these enhancements is added z-order support. To understand z-order, think first of x and y positioning. The x-y coordinate space places position (0, 0) at the top-left corner of the screen. Increasing the x value moves the position to the right. Increasing the y value moves the position down. Where does that leave position z? Z-order controls how components are drawn on top of one another. The 0 layer is the highest layer, or the one drawn last. Layer 1 is next, then 2, and so on. How is all this controlled? The Container component in the java.awt package provides two new methods: setComponentZOrder(Component c, int layer) and getComponentZOrder(Component c). These two methods allow you to work with the z-order feature. To demonstrate, the following program, ZOrder, creates three buttons named top, middle, and bottom. To get the button named top drawn at the top, and bottom on the bottom, the program adds the components as follows: contentPane.setComponentZOrder(top, 0); contentPane.setComponentZOrder(middle, 1); contentPane.setComponentZOrder(bottom, 2); Note that the z-order only matters when the components overlap. In this case, the program disables the layout manager and manually positions the components. When components overlap, be sure their container returns false from the isOptimizedDrawingEnabled() method that is inherited from JComponent. This ensures that lower z-order components are not drawn on top of higher components. In the following program, ZOrder, a new content pane is created with that behavior. You must subclass because there is no setter method. import java.awt.*; import javax.swing.*; public class ZOrder { public static void main(String args[]) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new JFrame("Z-Order"); 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=50; 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); } }); } } If you want to put the bottom button at the top, and the top button on the bottom, you simply do the following: contentPane.setComponentZOrder(bottom, 0); contentPane.setComponentZOrder(middle, 1); contentPane.setComponentZOrder(top, 2); or contentPane.setComponentZOrder(top, 2); contentPane.setComponentZOrder(middle, 1); contentPane.setComponentZOrder(bottom, 0); Because the z-order is defined in the Container class, this works with both lightweight Swing components and heavyweight AWT components. This isn't perfectly clear from the javadoc, which states in the setComponentZOrder method: This property is guaranteed to apply only to lightweight non-Container components. Note: Not all platforms support changing the z-order of heavyweight components from one container into another without the call to removeNotify. There is no way to detect whether a platform supports this, so developers shouldn't make any assumptions. The issue applies only to the specific comment about maintaining focus during z-order change that is mentioned immediately prior to the note. It does not apply to z-order not working with heavyweight components. The following program, ZOrderAWT, utilizes AWT components (instead of Swing) to demonstrate the z-order behavior. Notice that you don't have to worry about optimized drawing with AWT. import java.awt.*; import java.awt.event.*; public class ZOrderAWT { public static void main(String args[]) { EventQueue.invokeLater(new Runnable() { public void run() { Frame frame = new Frame("Z-Order"); WindowListener windowListener = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(windowListener); frame.setLayout(null); Button top = new Button("Top"); Button middle = new Button("Middle"); Button bottom = new Button("Bottom"); int x=25; int y=50; 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); frame.add(top); frame.add(middle); frame.add(bottom); frame.setComponentZOrder(bottom, 0); frame.setComponentZOrder(middle, 1); frame.setComponentZOrder(top, 2); frame.setSize(300, 200); frame.setVisible(true); } }); } } For more information about z-order support as well as other AWT enhancements, see "AWT Enhancements in the Java 2 Platform Standard Edition 5.0" (http://java.sun.com/j2se/1.5.0/docs/guide/awt/1.5/index.html). Also see the javadoc for the java.awt.Container class (http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Container.html). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CUSTOMIZING WINDOW ADORNMENTS Prior to the 1.4 release of J2SE, all dialogs and frames were created with titlebars that included platform-specific decorations. For instance, on a Microsoft Windows platform, the titlebar displayed an icon on the left and a title to its right. Window control decorations were displayed on the right side of the title bar: up to three gray boxes, one box each for minimize, maximize and close operations (depending on which were supported by the current window). However you couldn't control the appearance of the decorations because they were drawn by the system. However with the J2SE 1.4 release, this changed. Specifically, J2SE 1.4 added support for undecorated frames and dialogs. For example, you could now create a frame, and before showing it, call setUndecorated(true). This results in a frame without the platform-specific adornments, as illustrated in the following example: import java.awt.*; import javax.swing.*; public class EmptySample { public static void main(final String args[]) { Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("Empty"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setUndecorated(true); frame.setSize(300, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } } Theoretically, at this point you could create your own title bar. But, you don't have to. At least, not if your look and feel is Metal. The getSupportsWindowDecorations method of the MetalLookAndFeel reports true, which means that you can ask the look and feel to provide the title bar for you. To do that, you call the setDefaultLookAndFeelDecorated method of JFrame or JDialog. This provides a hint to newly-created frames or dialogs. If the look and feel supports providing window decorations, the hint tells it to use those decorations instead of the native ones. If the look and feel does not support providing window decorations, the hint is ignored. The following program, AdornSample, uses the title bar provided by the system look and feel, rather than calling setUndecorated(true) and creating its own title bar: import java.awt.*; import javax.swing.*; public class AdornSample { public static void main(final String args[]) { Runnable runner = new Runnable() { public void run() { // specify that newly created JFrames should be // decorated by the L&F JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Adornment Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } } Swing provides a level of control over which title bar to use. However, this requires a little more work than simply directing JFrame to use the default style from the look and feel. You have to tell the frame to be undecorated and tell its root pane how to decorate the frame. You do this through the following methods: frame.setUndecorated(true); frame.getRootPane().setWindowDecorationStyle(XXX); The parameter represented as XXX in setWindowDecorationStyle can be one of nine constants of the JRootPane class: o COLOR_CHOOSER_DIALOG o ERROR_DIALOG o FILE_CHOOSER_DIALOG o FRAME o INFORMATION_DIALOG o NONE o PLAIN_DIALOG o QUESTION_DIALOG o WARNING_DIALOG By passing the proper constant to the frame or dialog, a window can get a different title bar. In the following program, AdornSample2, uncomment different commented lines to try out the different styles: import java.awt.*; import javax.swing.*; public class AdornSample2 { public static void main(final String args[]) { Runnable runner = new Runnable() { public void run() { JFrame frame = new JFrame("Adornment Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setUndecorated(true); frame.getRootPane().setWindowDecorationStyle( // JRootPane.COLOR_CHOOSER_DIALOG); // JRootPane.ERROR_DIALOG); // JRootPane.FILE_CHOOSER_DIALOG); // JRootPane.FRAME); // JRootPane.INFORMATION_DIALOG); // JRootPane.NONE); JRootPane.PLAIN_DIALOG); // JRootPane.QUESTION_DIALOG); // JRootPane.WARNING_DIALOG); frame.setSize(300, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } } Calling setDefaultLookAndFeelDecorated(true) for a JDialog doesn't only control the title pane for the dialogs you create directly. It also controls the title pane for those generated by the JOptionPane. So you don't have to set the root pane window decoration style to WARNING_DIALOG. Instead, all you need to do is create a JOptionPane with a WARNING_MESSAGE. This is illustrated in the following program, WarnMe: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class WarnMe { public static void main(final String args[]) { Runnable runner = new Runnable() { public void run() { JDialog.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Show Warning"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton button = new JButton("Warn Me"); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { Object[] options = { "Run", "Walk", "Hide" }; JOptionPane.showOptionDialog( null, "Red Alert", "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); } }; button.addActionListener(listener); frame.add(button); frame.setSize(300, 100); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } } For more information on customizing the look and feel and using Swing, see the Java Foundation Classes (JFC) documentation page (http://java.sun.com/j2se/desktopjava/index.jsp). . . . . . . . . . . . . . . . . . . . . . . . IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ http://developers.sun.com/dispatcher.jsp?uid=6910008 * FEEDBACK Comments? Please enter your feedback on the Tech Tips at: http://developers.sun.com/contact/feedback.jsp?category=sdn * SUBSCRIBE/UNSUBSCRIBE Subscribe to other Java developer Tech Tips: - Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE). - Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME). To subscribe to these and other JDC publications: - Go to the Sun Developer Network - Subscriptions page, (https://softwarereg.sun.com/registration/developer/en_US/subscriptions), choose the newsletters you want to subscribe to and click "Submit". - To unsubscribe, go to the Subscriptions page, (https://softwarereg.sun.com/registration/developer/en_US/subscriptions), uncheck the appropriate checkbox, and click "Submit". - To use our one-click unsubscribe facility, see the link at the end of this email: - ARCHIVES You'll find the Core Java Technologies Tech Tips archives at: http://java.sun.com/developer/TechTips/index.html - COPYRIGHT Copyright 2005 Sun Microsystems, Inc. All rights reserved. 4150 Network Circle, Santa Clara, California 95054 USA. This document is protected by copyright. For more information, see: http://java.sun.com/developer/copyright.html Core Java Technologies Tech Tips January 18, 2005 Trademark Information: http://www.sun.com/suntrademarks/ Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.