Question: How many lines of code does it take to display a window?
Answer: One, but you’ll spend the rest of your life rewriting it.
OK, so it’s not a particularly funny joke, but it does get to the heart of why so many people originally embraced the Java platform’s promise of “write once, run anywhere.” Here’s a graphical user interface (GUI) development conundrum: each platform has a set of specific guidelines for what is considered the proper look and feel, yet users often want to access an application across multiple platforms. Just look at the variety of development tools described earlier; the installation for many IDEs, such as NetBeans, involves selecting which user interface you’d like to work with.
The long and the short of it is that there is no one right answer for GUI construction. From overt issues, such as the menu structure defaults (where is the placement of the Preferences menu item: the File, Edit, or Application menu?), to subtle ones, such as the default layout for dialog buttons, to paradigm decisions, such as requiring the use of the second mouse button—it’s hard to imagine a single approach to GUI application programming that would satisfy all application development needs.
Instead of focusing on the theoretical debate, it is often more useful to consider two key factors: the intended audience and the available resources. If you know that you will develop a consumer application on a large budget, you may wish to build a multimedia-style interface, with an emphasis on graphics, single-click actions, and lots of mouse-rollover responses. If you’re building a developer tool in your spare time, you’ll probably want to rely on standard Java Metal user interface objects. If you’re developing a general productivity application or an in-house application for a corporate environment, you may want to build and test for both Metal on Windows and Unix and Aqua on Mac OS X.
That said, it’s often easiest for GUI programmers to begin with the Mac OS X Aqua interface rather than the standard Metal look and feel. Perhaps the best reason to start with Aqua is its sheer number of default components. Aqua has one of the largest sets of defaults for spacing and fonts of any platform. If you start with Aqua, you’re less likely to have problems with other platforms (including both Motif and Windows) when you switch to Metal, because your defaults will all be set correctly. In addition, the graphics-intensive nature of the Aqua platform tends to push the limits of a graphics card; if your application responds well under Aqua, less sophisticated user interfaces should be at least as responsive, if not more so.
Swing is the user interface toolkit of Java Foundation Classes (JFC). When Sun developed the original version of Java, it introduced the Abstract Windowing Toolkit (AWT), which drew user interfaces based on an abstract layer that sat on top of the native windowing toolkit. This caused many problems, as the abstraction tended to blur when faced with the peculiarities of many windowing platforms. To resolve these issues, JFC and Swing were introduced as a more sophisticated toolkit with much better cross-platform support. JFC and Swing are based on AWT, so the core AWT is still part of Java. You could even write a pure AWT application, although there’s really no good reason to: if you’re developing a rich user interface you’ll want to stick to Swing APIs.
One of Swing’s most interesting aspects is its notion of a “pluggable” look and feel. The entire Unix world has a high degree of customizability, at the cost of a staggering variety of different approaches to user interface design. At first, these custom behaviors and functionality seem ideal, but they soon become a headache for developers and users. To deal with this issue, Swing introduced a standard look and feel called “Metal” that provides a reasonably attractive user interface for all platforms. Metal looks the same, more or less pixel-for-pixel, on all supported platforms.
However, it is still possible to override Metal and use a custom look and feel instead. Windows users may choose to add a Windows-specific look and feel to their application instead of going with the standard Metal. On Mac OS X, the obvious choice is the native Aqua look and feel. Apple has done an excellent job with their implementation of the Java-based Aqua look and feel, with many graphical operations featuring native hardware acceleration.
Therefore, when developing applications in Java, it is useful to determine what your supported look and feel options are going to be. While it’s possible to say that you intend to support Metal, Aqua, Motif, and Windows look and feel selections, you’ll wind up having to test your application’s appearance (including the length of localized strings—you were planning on making your application localizable, right?) on each supported look and feel. This is largely a matter of budget and resources, but in this section we will focus on comparisons between the standard Metal look and feel and the Mac OS X Aqua look and feel.
You may notice that, by default, Java applications on Mac OS X have the Aqua look and feel instead of Metal. This is a result of the default being set in a Mac OS X properties file (/Library/Java/Home/lib/swing.properties). If you wish, you could change the look and feel default to Metal, but in the interests of keeping your system as “virginal” as possible, it is probably best to change the settings on a per-application basis.
Tip
You’ll notice that this chapter does not detail the basics of Swing programming; instead, I’ve focused on the specifics of Swing as they relate to Aqua. If you’re not comfortable in Swing land, you might want to pick up Java Swing, by Eckstein, Loy, and Wood (O’Reilly).
You can specify the default look and feel for a specific application in several different ways. Chapter 3 created scripts that specified two ways to launch the NetBeans IDE. Looking at the scripts, you can learn how to set the JDK and the default look and feel. While this may work for some applications, scripts like this are poor form and should be avoided for commercial (or even in-house) deployment. Instead, use global properties files (as Mac OS X does) or some other static method. It’s a real pain to have to keep multiple versions of startup scripts, or to select a look and feel every time you start up an application.
The best way to get a sense of the Aqua look and feel is to examine the SwingSet2 demo application. On Mac OS X, you should find this application at /Developer/Examples/Java/JFC/SwingSet2/SwingSet2.
If you view the application with the Terminal, you will notice that SwingSet2 actually appears as SwingSet2.app, which is in turn a directory. Chapter 10 will explore this topic more thoroughly. For now, double-click the SwingSet2 icon in the Finder.
The application may take some time to launch, but when it does, you should see the sample output shown in Figure 4-1.
Playing around a bit with this application, you’ll
see that it is built on an instance of
JDesktopPane
. You should also notice that the
application is a miniature version of a Mac OS X desktop, complete
with a rather strange “mini-dock”
at the top of the application interface. This is an odd arrangement,
and it’s a user interface concept you
won’t find referenced anywhere in
Apple’s documentation (aside from an admonishment in
a README file against using it!).
It’s clearly provided for compatibility with
multiple
document interface (MDI) applications from other platforms, but is
unlikely to be satisfactory for any real GUI programming task.
Tip
If you’re
wondering how I knew that this application used a
JDesktopPane
, I simply clicked the
“Source Code” tab on the
application. There is also a src
folder in the SwingSet2
directory, which includes the source for the application.
Clicking on the second icon in the SwingSet2 button bar, we immediately confront the largest issue of the Aqua GUI: the radical difference in size required by common user-interface elements.
As you can see by comparing Figure 4-2 and Figure 4-3, the Aqua version of these buttons requires almost 50 percent more horizontal screen space than does the Metal version. This can reduce a nicely laid out Metal interface to a jumble of clipped text and ugly ellipses when converted to Aqua.
In Aqua, buttons by default have a gap of 12 pixels between them and are based on a 13-point font. This font can be a bit large when compared with other platform defaults. Rather than settling for a nasty-looking Metal interface based on these patterns, you may wish to standardize the “utility” UI patterns in Aqua for your Java applications. These smaller controls are closer to the control sizes of other platforms, and look good on Metal as well as Aqua. To support this smaller utility user interface, use controls based on an 11-point font and use a default control spacing of 8 pixels.
Another interesting contrast between Aqua
and Metal can be found when comparing
JList
implementations (the seventh
button from the left in the SwingSet2 mini-dock).
If you compare the user interface components in Figure 4-4 with those in Figure 4-5, you can see that while elements in the Aqua implementation are generally wider than those in Metal, they are often vertically shorter. So although Aqua interface widgets generally require more space than their Metal counterparts, this is not always the case.
The moral here is to be extremely careful when designing user interfaces for multiple look and feel motifs. The next section shows how you can minimize these problems.
Unfortunately, many developers test their applications with the Metal look and feel, ignoring other platforms and look and feel packages. While that may be acceptable for Windows or Motif users, the Aqua look and feel implementation is excellent, and there is no reason not to test for and support it.
As pointed out so glaringly in the last section, the biggest issue you need to deal with is sizing elements. When you first run your application under Aqua, you may be taken aback by the number of places where element size will affect you—from buttons that are clipped short with an ellipse, to navigation tabs that are now centered and occupying two levels, to portions of the user interface that are now unusable or even completely hidden. All things are not created equal on Aqua and Metal.
If you are bringing an application over from another platform, this may be a good time to examine the interface. Often, an application that looks too busy on Aqua is actually too busy on all platforms; Aqua is just driving the point home, especially when compared to the quality of the user interface work put into other Mac OS X applications.
The bad news is that no mantra or special set of steps can convert a Metal-size application to an Aqua-size one. That means that you’ll have to dig into your code by hand and space things out until they look good on Aqua. Be sure to use the “utility” UI patterns, which dictate 11-point fonts and 8-pixel spacings. The good news, though, is that you’ll end up with a better-designed application, and reap the benefits of both look and feel motifs.
The default Aqua
implementation of a JFrame
is set to the textured
background common to many Aqua applications. However, most developers
prefer to use a plain white background, like one
you’d see in a Finder folder or the various mail
applications. To set the background to white (or some other color),
you will need to use the following in your Swing code:
myJFrame.getContentPane( ).setBackground(java.awt.Color.white);
This explicit color setting ensures that defaults on different platforms don’t change your application’s background color without your knowing about it.
Another difference between Mac OS X and other platforms is that Mac OS X applications consistently use a small dot to indicate when a window is “dirty,” meaning that information has been changed and a save is in order. Figure 4-6 shows a “dirty” window icon, and Figure 4-7 shows the same icon once a save has been completed.
To set this “dirty” dot, use the following code:
myJFrame.getRootPane( ).putClientProperty("windowModified", Boolean.TRUE);
Use the following line to clear the dot after a save has occurred:
myJFrame.getRootPane( ).putClientProperty("windowModified", Boolean.FALSE);
The last major issue to think about is the location of actions on a menu bar. The standard Mac OS X menu bar is typically organized by the scope of the action. For example, consider the menu hierarchy detailed in Table 4-1, which indicates a menu bar’s headings and the scope that each heading’s actions should govern.
Table 4-1. Menu headings and their scope
Menu heading |
Scope |
Examples |
---|---|---|
Apple menu |
Entire system (including global actions) |
Restart, Sleep |
Application |
Entire application |
Quit, Preferences, Hide, About |
File |
Entire document |
New, Save, Print |
Edit |
Section of document |
Find, Replace |
Format |
Changes appearance but not data |
Font, Alignment |
Window |
Switches between documents |
Tile, Cascade, Go To |
Help |
No effect on application, but easy to find |
Help, Documentation |
If you use these scopes as a standard set of rules for your own menu locations and choices, you’ll find that users intuitively know where to look for items and will feel at home with your application quickly.
Get Mac OS X for Java Geeks now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.