User Interface Toolkits for Java

This article discusses how the OS X implementation of the user interface toolkits Swing, AWT, accessibility, and sound differ from the toolkits on other platforms. Although there is some additional functionality in OS X, for the most part these toolkits work as you would expect them to on other platforms. This article does not discuss user interface design issues that you should consider in OS X. For that information, see “Making User Interface Decisions.”

Swing

In OS X, Swing uses the Aqua Look and Feel as the default look and feel (LAF). Swing attempts to be platform neutral, but some aspects of it are an impedance mismatch with the Aqua user interface. Apple attempts to bridge the gap with a common ground that provides both developers and users an experience that is not foreign. This section discusses where the Aqua LAF differs from the default implementation on other platforms.

Menu Bars (JMenuBar)

In Java’s default cross-platform LAF, as well as the Windows LAF, menus are applied on a per-frame basis inside the window under the title bar. On a Mac, in contrast, menus appear in one spot no matter what windows users have open—at the top of the screen, in the menu bar.

To get menus out of the window and into the menu bar, you need only to set a single system property:

apple.laf.useScreenMenuBar

This property can have a value of true or false. By default, it is false, which means menus are in the window instead of the menu bar. When this property is set to true, the Java runtime moves the menu bar of any Java frame to the top of the screen, where Macintosh users expect it. Since this is just a simple runtime property that only the OS X Java VM looks for, there is no harm in putting it into your cross-platform code base.

Note that this setting does not work for Java dialogs having menus. A dialog should be informational or present the user with a simple decision, not provide complex choices. If users are performing actions in a dialog, it is not really a dialog and you should consider using a JFrame object instead of a JDialog object.

Tabbed Panes (JTabbedPane)

On other platforms, if you have a tabbed pane (JTabbedPane) with too many tabs to fit in the parent window, the tabs are simply stacked on top of each other. In the Aqua user interface of OS X, tab controls are never stacked. The Aqua LAF implementation of multiple tabs includes a special tab on the right that exposes a pull-down menu to navigate to the tabbed panes not visible. This behavior, allows you to program your application just as you would on any other platform while providing users an experience that is more consistent with OS X guidelines. The difference between a tabbed pane in OS X and a tabbed pane in Windows is shown in Figure 1.

Figure 1  Tabbed panes with multiple tabs in OS X and Windows
A tabbed pane with multiple tabs on another platform

One other thing to keep in mind about JTabbedPane objects in OS X is that they have a standard size. If you put an image in a tab, the image is scaled to fit the tab instead of the tab to the image. This standard size applies to several other Swing components as well.

Component Sizing

Aqua has very well-defined guidelines for the size of its controls. Swing, on the other hand, does not. The Aqua LAF tries to find a common ground. For example, since any combo box larger than twenty pixels would look out of place in OS X, that is all that is displayed, even if the actual size of the combo box is bigger. Figure 2 shows a very large JComboBox component in Windows XP. Note that the drop-down scrolling list appears at the bottom of the button.

Figure 2  An oversize JComboBox component in Windows
Oversize JComboBox in Windows

The same code yields quite a different look in OS X, as can be seen in Figure 3. The visible button is sized to that of a standard Aqua combo box. The drop-down list appears at the bottom of the visible button. The entire area that is active on other platforms is still active, but the button itself doesn’t appear as large.

Figure 3  An oversize JComboBox component in the Aqua LAF
Oversize JComboBox in the Aqua LAF

Note that some other components have similar sizing adjustments to align with the standards set in OS X Human Interface Guidelines for example, scroller and sliders. The JComboBox example is an extreme example. Most are not as large, but this gives you an idea of how the Aqua LAF handles this type of situation.

Buttons

There are basically three button types in OS X:

  • Push buttons, which are rounded rectangles with text labels on them.

  • Radio buttons, which are in sets of two to seven circular buttons. They are for making mutually exclusive, but related choices.

  • Bevel buttons, which can display text, an icon, or a picture that can be either a standard push button or have a menu attached.

    Bevel buttons normally have rounded corners. When displayed in a toolbar or when sizing constraints are tight, the corners are squared off.

To be consistent with these button types and their defined use in OS X, there are some nuances of Swing buttons that you should be aware of:

  • JButton components with images in them are rendered as bevel buttons by default.

  • A default JButton component that contains only text is usually rendered as a push button. (Over a certain height, it is rendered as a bevel button, since Aqua push buttons are limited in their height.)

In addition to these default characteristics which are dependent on height and the contents of the button, you can also explicitly set the type of button with JButton.buttontype, which accepts the following values:

  • square gives you square bevel button.

  • bevel gives you a rounded bevel button.

  • texturedRound gives you a metal button.

Keep Apple’s human interface guidelines in mind if you explicitly set a button type.

For many more button styles available in the Aqua LAF in Swing, see New Control Styles available within J2SE 5.0 on Mac OS X 10.5.

Abstract Window Toolkit (AWT)

By its nature, AWT is very different on every platform. When developing Java applications in OS X, follow these tips for best results:

Character Encoding

The default character encoding in Java for OS X is MacRoman. The default font encoding on some other platforms is ISO-Latin-1 or WinLatin-1; unlike MacRoman, these encodings are subsets of UTF-8. Programs that assume that filenames can be turned into UTF-8 by just turning a byte into a char will cause problems in OS X.

The simplest way to work around this problem is to specify a font encoding explicitly rather than assuming one. Specifying a font encoding besides UTF-8 and UTF-16 is not recommended.

If you do not specify a font encoding explicitly, recognize that:

Accessibility

With some platforms, to use the Java Accessibility API, you must use a native bridge. This is not necessary in OS X because the bridging code is built in. Users can configure the accessibility features of OS X through the Universal Access pane of System Preferences. As a result, if you are using the Accessibility API, your application can use devices that the user has configured there.

Beginning with OS X v10.4, a screen reader called VoiceOver is included with the operating system. Your Java application automatically uses this technology.

Security

In OS X v10.5 and later, Java applications that use the Kerberos computer network authentication protocol automatically access the system credentials cache and tickets.

Apple also includes a cryptographic service provider based on the Java Cryptography Architecture. Currently, the following algorithms are supported:

Java on OS X v10.5 features an implementation of KeyStore that uses the OS X Keychain as its permanent store. You can get an instance of this implementation by using code like this:

keyStore = KeyStore.getInstance("KeychainStore", "Apple");

For more usage information, see the reference documentation on java.security.KeyStore at http://java.sun.com/j2se/1.5.0/docs/api/java/security/KeyStore.html.

Sound

Java on OS X allows you to sample sound with Apple’s Core Audio framework at any frame rate supported by your input device. Input can be signed or unsigned PCM encoding, mono or stereo, 8 or 16 bits per sample.

By default, the Java Sound engine in OS X uses the midsize sound bank from http://java.sun.com/products/java-media/sound/soundbanks.html.

Input Methods

OS X supports Java input methods. The utility application Java Preferences allows you to configure a trigger for input methods. You can download sample Java-specific input methods from http://java.sun.com/products/jfc/tsc/articles/InputMethod/inputmethod.html.

Java 2D

In OS X, Java windows are double buffered. The Java implementation itself attempts to flush the buffer to the screen often enough to have good drawing behavior without compromising performance. If, for some reason, you need to force window buffers to be flushed immediately, use Toolkit.sync().

By default, Java on OS X uses the Sun2D renderer, which exactly mimics the behavior of Java 2D on other platforms. If you are developing a graphically intensive application specifically for the Mac and the Sun2D renderer’s performance is inadequate, you may find better success using Apple’s Quartz graphics engine for your Java rendering instead (see Quartz 2D Programming Guide for more information). Quartz is optimized for a different set of operations from the Sun2D renderer, and its behavior is sometimes different from that of Java on other platforms.

By default, Quartz displays text anti-aliased. Therefore, if you use Quartz as your renderer, Java2D turns anti-aliasing on in order to render text in the Aqua look and feel for Swing (it does this by setting KEY_ANTIALIASING to VALUE_ANTIALIAS_ON). If you want the pixels of your images and text to more closely approximate that same content on other platforms, turn off anti-aliasing. You can do so by using the properties described in Java System Properties or by calling java.awt.Graphics.setRenderingHint() from within your Java application. In applets, anti-aliasing is turned off by default.

Resolution Independence

Java is not explicitly designed for resolution independence (also known as HiDPI); therefore, Java for OS X borrows some functionality from the Cocoa framework. To load a resolution-independent tiff, icns, or pdf file from the Resources folder of your application bundle into your Java application, use the getImage() method of java.awt.Toolkit. The string you pass into getImage() is of the form "NSImage://MyImage". Do not include the file extension of the image. Also be aware that the Sun 2D renderer is disabled when the user interface scale factor does not have a value of 1.0. Use the Quartz renderer so that your images scale smoothly.

You can test resolution independence in your application with the Quartz Debug tool, located in /Developer/Applications/Performance Tools. Quartz Debug allows you to launch your application at up to three times the default screen resolution. For a full list of features included in Quartz Debug, consult the Quartz Debug Help.

OS X includes resolution-independent standard images for user interfaces that you can also access with the getImage method of java.awt.Toolkit. For instance, Toolkit.getDefaultToolkit().getImage("NSImage://NSColorPanel") will return an Image reference representing the color wheel icon seen on the Colors button in applications such as Mail. For a comprehensive list of the standard images available, see “Constants” in NSImage Class Reference.