Java tip: Problems and special features of the CDE/Motif look and feel, part 1

Technologies: Java 5+

The classic Java Swing CDE/Motif look and feel recreates the beveled buttons, gray color scheme, and light-weight design of the X11 window system's applications circa 1990. This article is part 1 of 4 and provides a component by component review of problems, workarounds, and special features of Java's CDE/Motif look and feel. Example images are included along with UIDefaults values, color swatches, and icon images.

This Part 1 article in the series reviews how to select the look and feel and access its UIDefaults, then starts an alphabetical run through its components from JButton through JEditorPane. Part 2 covers JFileChooser through JOptionPane. Part 3 covers JPanel through JSplitPane. And Part 4 covers JTabbedPane through JViewport.

Introducing the CDE/Motif look and feel

The Common Desktop Environment (CDE) was a UNIX window manager and set of desktop tools built atop the X11 Window System and the Motif user interface toolkit. Built in the 1980s and 1990s when computer displays were rarely capable of 24-bit colors, the Motif toolkit used a limited gray color palette and simple beveled buttons and panels.

The Java Swing CDE/Motif look and feel mimics Motif and is included in all standard Java distributions, though it's rarely used. The look and feel is cross-platform and it looks and works the same on the Mac, all recent versions of Windows, and on Linux, Solaris, and FreeBSD with either Gnome or KDE.

CDE/Motif look and feel sample
A sample of the Java CDE/Motif look and feel.

While CDE/Motif's beveled gray look is bland and clunky by today's standards, the look and feel is easily customized to use your own choice of colors. Contrast this with the Nimbus look and feel, or those designed to mimic the Mac and Windows look and feels. These alternatives look slicker than CDE/Motif, but they impose a glossy style that cannot be modified easily to use your own color scheme.

Selecting the CDE/Motif look and feel

To select the look and feel, you need the CDE/Motif implementation's class name. While the class name hasn't changed in years and is the same for all platforms, it's rarely a good idea to hardcode class names as literals. Instead, look it up at run time using the array of UIManager.LookAndFeelInfo objects returned by UIManager.getInstalledLookAndFeels( ). Once the class name is in hand, call UIManager.setLookAndFeel( String name ):

for ( UIManager.LookAndFeelInfo info: UIManager.getInstalledLookAndFeels( ) )
{
	if ( info.getName( ).equals( "CDE/Motif" ) )
	{
		try
		{
			UIManager.setLookAndFeel( info.getClassName( ) );
		}
		catch ( Exception e )
		{
			// Deal with a missing or broken class.
		}
		break;
	}
}

Getting defaults for the CDE/Motif look and feel

A UIDefaults hash table contains important colors, fonts, icons, border styles, and dimensions used by a look and feel. The UIManager manages three of these UIDefaults hash tables with three overlapping sets of defaults:

  1. Developer defaults are application defaults added by the developer.
  2. Look and feel defaults are specific values set by the look and feel.
  3. System defaults are generic backup values provided by Swing.

Calling any of the get methods on UIManager looks through these three UIDefaults tables, in the above order, to find a named color, font, icon, border, or size. Developer defaults override look and feel defaults, and look and feel defaults override system defaults.

For instance, to get the button background color look up the value of "Button.background":

Color color = UIManager.getColor( "Button.background" );

For this article, we're interested solely in the UIDefaults provided by the CDE/Motif look and feel itself. To get these, call UIManager.getLookAndFeelDefaults( ):

UIDefaults defaults = UIManager.getLookAndFeelDefaults( );

Then query that defaults table:

Color color = defaults.getColor( "Button.background" );

Since UIDefaults subclasses java.util.Hashtable, you can get a list of defaults names from the hash table's key set. While keys are usually strings, they aren't always.

for ( Object key: defaults.keySet( ) )
	System.out.println( key.toString( ) );

Working with the CDE/Motif look and feel

Below begins an alphabetical run through the look and feel's UIDefaults and Swing components. Non-string keys and UI class values are implementation artifacts and are not included here.

JButton

Key Type Value
Button.background Color 174, 178, 195
Button.border Border javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
Button.darkShadow Color 0, 0, 0
Button.defaultButtonFollowsFocus Boolean true
Button.focusInputMap Input map javax.swing.plaf.InputMapUIResource
Button.font Font Dialog, 12.0
Button.foreground Color 0, 0, 0
Button.highlight Color 220, 222, 229
Button.light Color 220, 222, 229
Button.margin Insets 2, 4, 2, 4
Button.select Color 147, 151, 165
Button.shadow Color 99, 101, 111
Button.textIconGap Integer 4
Button.textShiftOffset Integer 0

Special features

  • The UIDefaults "Button.border" gives a border object that draws a button's beveled border, pink keyboard focus outline, and recessed groove for the default button. You can use the border to give a button-like look to any component, such as a JPanel, though it will only show pressed, focused, and default indicators on an AbstractButton subclass. This is useful when creating custom button-like components that need to blend in with the rest of the look and feel.

    Button.border

Problems

  • When a JButton is a JRootPane's default button, a recessed groove is drawn around the button. To leave room for this groove, the look and feel adds empty space around buttons marked with setDefaultCapable( true ), which affects the layout (other look and feels indicate the default by changing its color instead of its size so that the layout remains consistent for default capable, and incapable buttons).
  • There is no UIDefaults color for the pink outline indicating the keyboard focus. The color can be found in other components UIDefaults, such as "CheckBox.focus" or "RadioButton.focus".
  • A selected JButton always has a keyboard focus outline (other look and feels don't indicate a keyboard focus when a button is selected).
  • Buttons use narrow inner margins, which looks crowded. You can override margins using setMargin( Insets m ).

JCheckBox

Key Type Value
CheckBox.background Color 174, 178, 195
CheckBox.border Border javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
CheckBox.focus Color 178, 77, 122
CheckBox.focusInputMap Input map javax.swing.plaf.InputMapUIResource
CheckBox.font Font Dialog, 12.0
CheckBox.foreground Color 0, 0, 0
CheckBox.icon Icon com.sun.java.swing.plaf.motif.MotifIconFactory$CheckBoxIcon
CheckBox.margin Insets 4, 2, 4, 2
CheckBox.textIconGap Integer 8
CheckBox.textShiftOffset Integer 0

Special features

  • The UIDefaults "CheckBox.border" contains a border object that draws the keyboard focus outline and a beveled border, even though a check box doesn't have a beveled border. While the border can be used to create button-like extensions to AbstractButton, the border class in "Button.border" is probably a better choice.

    CheckBox.border
  • The UIDefaults "CheckBox.icon" contains the unchecked box outline with the default border.

    CheckBox.icon
    13 x 13

Problems

  • There are no UIDefaults icons for the flat border box style or for a check mark (this is typical for all look and feels). If you need these icons, create a JCheckBox component and paint it into the Graphics context of a BufferedImage. Then create an ImageIcon using that BufferedImage.
  • When a JCheckBox is disabled, its label is dimmed but not the check box or check. So, if you don't include a label on a check box (such as in a column of on/off checks in a table) the user can't tell if the component is disabled (other look and feels don't have this problem because they dim the check box too). If you need to show the disabled state on the check box and check, you can use your own icons to override the check box icon.
  • When a JCheckBox has the keyboard focus, it draws a pink outline around the entire component, including the label. When there's no label, this can look odd (other look and feels outline the check box itself, instead of the entire component). You can remove this border with setBorder( null ), but then there won't be any indication of the keyboard focus.
  • A JCheckBox draws an opaque background (some look and feels do and some don't). If you're using a colored parent container and need it to show through the component, you can disable the background with setOpaque( false ).

JCheckBoxMenuItem

Key Type Value
CheckBoxMenuItem.acceleratorFont Font Dialog, 12.0
CheckBoxMenuItem.acceleratorForeground Color 0, 0, 0
CheckBoxMenuItem.acceleratorSelectionForeground Color 0, 0, 0
CheckBoxMenuItem.arrowIcon Icon com.sun.java.swing.plaf.motif.MotifIconFactory$MenuItemArrowIcon
CheckBoxMenuItem.background Color 174, 178, 195
CheckBoxMenuItem.border Border javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
CheckBoxMenuItem.borderPainted Boolean false
CheckBoxMenuItem.checkIcon Icon com.sun.java.swing.plaf.motif.MotifIconFactory$CheckBoxIcon
CheckBoxMenuItem.font Font Dialog, 12.0
CheckBoxMenuItem.foreground Color 0, 0, 0
CheckBoxMenuItem.margin Insets 2, 2, 2, 2
CheckBoxMenuItem.selectionBackground Color 165, 165, 165
CheckBoxMenuItem.selectionForeground Color 0, 0, 0

Special features

  • The UIDefaults "CheckBoxMenuItem.border" contains a border object that draws the recessed border around a selected menu item.

    CheckBoxMenuItem.border
  • The UIDefaults "CheckBoxMenuItem.checkIcon" contains the unchecked box outline with the default border.

    CheckBoxMenuItem.checkIcon
    13 x 13

Problems

  • The UIDefaults "CheckBoxMenuItem.arrowIcon" is empty, but it isn't needed anyway (the icon is an implementation artifact that comes from using a common base class for all menu item implementations).
  • There is no UIDefaults icon for the check mark (this is typical for all look and feels).
  • Unlike a JCheckBox, setting the icon on a JCheckBoxMenuItem adds the icon beside the check box instead of replacing the check box icon (this is typical for all look and feels). There is no simple way to replace the check box icon itself.
  • If any menu item on a menu has an icon, all of the menu items leave room for the icon (most look and feels do this). This can look odd if a menu item has an icon but no label. To avoid this look, always give menu items labels.

JColorChooser

Key Type Value
ColorChooser.background Color 174, 178, 195
ColorChooser.font Font Dialog, 12.0
ColorChooser.foreground Color 0, 0, 0
ColorChooser.swatchesDefaultRecentColor Color 174, 178, 195
ColorChooser.swatchesRecentSwatchSize Dimension 10, 10
ColorChooser.swatchesSwatchSize Dimension 10, 10

Problems

  • The JColorChooser's background is an opaque gray (some look and feels draw an opaque background, and some do not). If you're embedding the component in a colored parent container you can set the color chooser's background to transparent with setOpaque( true ), and get the preview panel with getPreviewPanel( ) and change it too. While you can get the internal tab panels with getChooserPanels( ), making them transparent will look odd.
  • There is no disabled state for a JColorChooser. Calling setEnabled( false ) has no effect.

JComboBox

Key Type Value
ComboBox.ancestorInputMap Input map javax.swing.plaf.InputMapUIResource
ComboBox.background Color 174, 178, 195
ComboBox.border Border javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
ComboBox.buttonBackground Color 174, 178, 195
ComboBox.buttonDarkShadow Color 0, 0, 0
ComboBox.buttonHighlight Color 220, 222, 229
ComboBox.buttonShadow Color 99, 101, 111
ComboBox.control Color 174, 178, 195
ComboBox.controlForeground Color 0, 0, 0
ComboBox.disabledBackground Color 174, 178, 195
ComboBox.disabledForeground Color 128, 128, 128
ComboBox.font Font Dialog, 12.0
ComboBox.foreground Color 0, 0, 0
ComboBox.isEnterSelectablePopup Boolean false
ComboBox.selectionBackground Color 0, 0, 0
ComboBox.selectionForeground Color 255, 247, 233
ComboBox.timeFactor Long 1000

Special features

  • The UIDefaults "ComboBox.border" contains a border object that draws the beveled border and pink keyboard focus outline around the combo box.

    ComboBox.border

Problems

  • An editable JComboBox replaces the inner area with an editable text field, but its colors aren't in the JComboBox's UIDefaults and they don't match the colors for a JTextField. Oddly, the off-white background color matches that of a JToolTip or a selection for a JTree (other look and feels use text field colors for editable combo boxes).
  • A disabled JComboBox dims the combo text, but not the down arrow button. If the combo text is empty, the user cannot tell visually if the JComboBox is disabled(other look and feels dim the arrow button too).
  • An unfocused JComboBox has a one pixel wide gray border around it that matches the default gray background of JPanel and other containers. However, if you're using a different background color on the parent container, this gray border stands out as a gray halo. It cannot be disabled except by overriding the component's border with setBorder( Border b ), but that will override the pink keyboard focus outline too.
  • There is no UIDefaults color for the pink outline indicating the keyboard focus. The color can be found on other components, such as "CheckBox.focus" or "RadioButton.focus".
  • There is no UIDefaults icon for the down arrow button (some look and feels provide one, but most do not).

JDesktop

Key Type Value
Desktop.ancestorInputMap Input map javax.swing.plaf.InputMapUIResource
Desktop.background Color 0, 92, 92
Desktop.minOnScreenInsets Insets 3, 3, 3, 3
DesktopIcon.icon Icon sun.swing.ImageIconUIResource
DesktopIcon.windowBindings Array java.lang.Object

Special features

  • The UIDefaults "DesktopIcon.icon" provides the icon for iconified internal frames. Unfortunately, it's ugly (most look and feels iconify to a row of buttons along the bottom instead of labeled icons).

    DesktopIcon.icon
    48 x 48

Problems

  • Disabling the JDesktopPane has no visible effect (most look and feels have a visible disabled desktop effect).
  • There is no way to set the desktop icon for an iconified JInternalFrame. The JDesktopPane default icon is always used (most look and feels will use the internal frame's icon as the desktop icon).
  • The look and feel of the desktop has nothing to do with the conventions of the native platform, so users may be confused about how to move, resize, iconify, un-iconify, and close inner frames. For most platforms the notion of internal frames on a JDesktopPane is considered very poor user interface style. The class probably should never be used.

JEditorPane

Key Type Value
EditorPane.background Color 255, 255, 255
EditorPane.border Border javax.swing.plaf.basic.BasicBorders$MarginBorder
EditorPane.caretBlinkRate Integer 500
EditorPane.caretForeground Color 255, 0, 0
EditorPane.focusInputMap Input map javax.swing.plaf.InputMapUIResource
EditorPane.font Font Serif, 12.0
EditorPane.foreground Color 0, 0, 0
EditorPane.inactiveForeground Color 128, 128, 128
EditorPane.margin Insets 3, 3, 3, 3
EditorPane.selectionBackground Color 192, 192, 192
EditorPane.selectionForeground Color 255, 247, 233

Note: JEditorPane is shown above within a JScrollPane, as it is typically used. The first row is selected.

Problems

  • An editable JEditorPane indicates the keyboard focus by adding a red caret instead of the black caret used by other text components. The component doesn't draw the pink outline used by other components to indicate they have the focus.
  • Text selections are only visible when the component is enabled and focused (most look and feels act the same).
  • The margins are crowded, but can be changed using setMargin( Insets m ).
  • JEditorPane and JTextPane both default to the generic "Serif" font, but all other text components default to "SansSerif". And all labels, button text, menu items, etc., default to the "Dialog" font, which is also sans-serif. You can override this inconsistency with setFont( Font f ).
  • Selected text colors have poor contrast (white on light gray) and they differ from those used by other text components (black on white instead of black on gray) (other look and feels use consistent colors across all text components). You can change the component's colors using setForeground( Color c ), setBackground( Color c ), setSelectionColor( Color c ), and setSelectedTextColor( Color c ).

Downloads

The CDE/Motif UIDefaults colors are available for download in the X11 rgb.txt file format:

Further reading

Related articles at NadeauSoftware.com

Web articles

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

Nadeau software consulting
Nadeau software consulting