This article discusses how the Mac 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 Mac 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 Mac OS X. For that information, see “Making User Interface Decisions.”
Swing
Abstract Window Toolkit (AWT)
Character Encoding
Accessibility
Security
Sound
Input Methods
Java 2D
Resolution Independence
In Mac 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.
Note: While testing your application, you should test it on the standard Java cross-platform LAF as well as Aqua. To do this, add UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassname())
to your code.
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 Mac 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.
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 Mac 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 Mac OS X guidelines. The difference between a tabbed pane in Mac OS X and a tabbed pane in Windows is shown in Figure 1.
One other thing to keep in mind about JTabbedPane
objects in Mac 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.
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 Mac 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.
The same code yields quite a different look in Mac 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.
Note that some other components have similar sizing adjustments to align with the standards set in Apple 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.
There are basically three button types in Mac 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 Mac 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.)
JButton
components in a toolbar are rendered as bevel buttons with square, not rounded, edges.
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 three values:
toolbar
gives you square bevel button.
text
gives you a push button.
icon
gives you a rounded bevel button.
Keep Apple’s human interface guidelines in mind if you explicitly set a button type.
For a more thorough treatment of the Aqua LAF in Swing, see New Control Styles available within J2SE 5.0 on Mac OS X 10.5.
By its nature, AWT is very different on every platform. When developing Java applications in Mac OS X, follow these tips for best results:
The value of the accelerator key can be determined by calling Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
. This is further discussed in “ Accelerators (Keyboard Shortcuts).”
Mac OS X does not specify a default minimum size for windows. To avoid a 0 by 0 (0x0) pixel window being opened, top-level frames have a minimum size of 128 by 37 (128x37).
java.awt.GraphicsDevice
includes methods for controlling the full screen of a client computer through Java. In addition to these standard tools, Mac OS X provides a few system properties that may be useful for development of full-screen Java applications. These are discussed in Java System Properties.
The default character encoding in Java for Mac 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 Mac OS X.
The simplest way to work around this problem is to specify a font encoding explicitly rather than assuming one.
If you do not specify a font encoding explicitly, recognize that:
In the conversion from a Unicode subset to MacRoman you may lose information.
Filenames are not stored on disk in the default font encoding, but in UTF-8. Usually this isn’t a problem, because most files are handled in Java as java.io.File
s, though it is good to be aware of.
Although filenames are stored on disk as UTF-8, they are stored decomposed. This means that certain characters—for example, e-acute (é)—are stored as two characters, “e”, followed by “´” (acute accent). The default HFS+ filesystem of Mac OS X enforces this behavior. SMB enforces composed Unicode characters. UFS and NFS do not specify whether filenames are stored composed or decomposed, so they can do either.
With some platforms, to use the Java Accessibility API, you must use a native bridge. This is not necessary in Mac OS X because the bridging code is built in. Users can configure the accessibility features of Mac 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 Mac OS X v10.4, a screen reader called VoiceOver is included with the operating system. Your Java application automatically uses this technology.
In Mac OS X v10.5, 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:
Mac: MD5, SHA1
Message Digest: MD5, SHA1
Secure Random: YarrowPRNG
Java on Mac OS X v10.5 features an implementation of KeyStore that uses the Mac 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.
Java on Mac 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 Mac OS X uses the midsize
sound bank from http://java.sun.com/products/java-media/sound/soundbanks.html.
Mac OS X supports Java input methods. The utility application Input Method Hot Key, installed in /Applications/Utilities/Java/
, allows you to configure a trigger for input methods. You can download sample input methods from http://java.sun.com/products/jfc/tsc/articles/InputMethod/inputmethod.html.
In Mac 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 Mac 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 OS X platform 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 http://developer.apple.com/graphicsimaging/quartz/ for more information). Quartz is optimized for a different set of operations from the Sun2D renderer, and as a consequence its behavior is by no means identical to 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.
Tip: When you are using anti-aliasing, if you need to replace text or an image, repaint the graphics context. Do not use XOR mode to repaint images.
Java is not explicitly designed for resolution independence (also known as HiDPI); therefore, Java for Mac 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 if you are using the Sun2D renderer, Java will automatically switch to the Quartz engine and enable anti-aliasing if you load a resolution-independent image.
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.
Mac 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.
Note: The standard image constants defined in NSImage.h
all include the substring ImageName
. For instance, the constant for the NSColorPanel
image has the name NSImageNameColorPanel
. When passing a string to getImage
, do not include ImageName
in the string—it is included in the name of the Objective-C constant, but not the value of the name itself.
© 2003, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-10-15)