HTML Markup | JavaScript | Java | Computer Sci | Home & Links

Tutorial 13 - Designing Swing GUIs

As soon as you have more than one or two widgets (ie components or controls), you need to arrange them in a logical and pleasing way. GUI design in Java relies on a layered approach where each layer uses an appropriate layout manager. Colors, fonts and borders add attractiveness. Look-and-feel lets the designer control the control rendering. This tutorial explores some of the issues and methods involved in designing reusable GUIs.

Colors and Fonts

Colors can be selected from the awt Color class constants: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, white, yellow, BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, ORANGE, PINK, RED, WHITE, YELLOW.
Note: The names do not match the basic sixteen colors system.

Custom colors with transparency can be created using the constructor Color(red, green, blue, [alpha]) where the parameters are integer [0 - 255] or float [0.0 - 1.0]. An alpha of 255 or 1.0 yields opaque [default]. For example: skyblue is 135,206,235 (ie. 87CEEB hex).

Text colors are set with either the setColor(color_obj) or the setForeGround(color_obj) method depending on the object. Background colors are set with setBackground(color_obj).

Object colors can be read using the integer methods: getRGB(), getRed(), getGreen(), getBlue() and getAlpha().

Font settings use awt Font class objects.

Font bigFont=new Font("TimesRoman",Font.ITALIC,24);

Note that the parameters are family, style (as a Font class constant) and point size. Style is one of PLAIN, ITALIC or BOLD. Other objects can use the new font style by calling the setFont(fontObject) method.

FontMetrics defines a class that accesses the height information of a font in pixels. The class methods are: getLeading(), getAscent(), getDescent() and getHeight() [overall dimension].

Borders and Separators

Borders are used to separate or group widgets in a logical manner. They also 'dress up' the GUI. Border classes are imported from the javax.swing.border package. BevelBorder and SoftBevelBorder can be applied to buttons to give them a 3D look. EmptyBorder is used to 'pad' a widget with spacing. EtchedBorder and LineBorder separate widgets or panes for logical grouping. MatteBorder allows images or colors to be used to construct the border areas. TitledBorder allows adding a 'fieldset' frame and a 'legend' caption to an object such as a button group. An example of a titled border object is:

Border blackline=BorderFactory.createLineBorder(Color.black);
TitledBorder tb=new TitledBorder(border,"legend");

Any object can use the setBorder(border_obj) method to establish a border around it.

Line separators are used for visual separation of components in a panel. They are constructed with JSeparator(orient). Orient is either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.

Component Sizing

In most cases, component size is determined automatically by content and layout managers. But in some instances a specific size is wanted. The setSize(x,y) method is the obvious but incorrect choice. The setPreferedSize() method is appropriate.

Look and Feel

Swing allows three rendering modes: a unified 'Java' look and feel [the default], the native platform look, or a specific platform's look. If you want to change from the default to the native platform look, add the following at the start of the driver class main method:

  try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
  catch (Exception e) { }

If you want to use a look other than the default or the native one, you must first check for what's available. For copyright reasons, the Mac view is not available in Windows and vice versa. To check what is available use:

UIManager.LookAndFeelInfo[] laf=UIManager.GetInstalledLookAndFeels();
for (int i=0;i<laf.length;i++)
    { System.out.println("Class name: "+laf[i].getClassName());
      System.out.println("Name: "+laf[i].getName());}

If you want to change the look after starting (for example letting the user select the look) be sure to make all components update their appearance. Call the SwingUtilities class method updateComponentTreeUI(Component) with the main user interface component such as a JFrame object as the argument.

Layout Managers

Layout managers are classes that control the size, positioning and alignment of components within a container so that they neither crowd each other nor overlap. Containers can also be components and thus layered (ie layout managers within layout managers). Java provides layout managers that range from the simple FlowLayout, BoxLayout and GridLayout to the special purpose BorderLayout and CardLayout to the very flexible GridBagLayout. SpringLayout is a new layout manager that uses the concepts of springs and struts to help design well-positioned containers. Use the setLayout() method to reset a content pane to a specific layout manager:

JPanel p=new JPanel();         // make the pane first
p.setLayout(new BorderLayout()); // then reset manager

Each layout manager scales components on resize in a different manner. Use the setMinimumSize(w,h) method on the frame to prevent wrap or loss of component display.

FlowLayout is used to arrange components in rows across the width of a container. FlowLayout components automatically wrap or move to the next row when required. When you use FlowLayout, each component retains its default size (i.e. a JButton will be large enough to hold its text), unlike BorderLayout where the components you add fill their regions. Also, with FlowLayout, when you resize the window, each component retains its size (but it might become partially obscured or change position or wrap). If you need to force a wrap (such as using <br> in HTML), use two containers, one for each line. FlowLayout is the default for JPanel objects. FlowLayout components are center justified by default. If you require left justification of components, reset the layout alignment with:

setLayout(new FlowLayout(FlowLayout.LEFT));

BoxLayout places items in a single row or column. Glue can be added as a flexible space filler using the methods Box.createGlue(), Box.createHorizontalGlue() and Box.createVerticalGlue(). Struts can be added as a fixed space filler using the methods createRigidArea(dim), createHorizontalStrut(w) and createVerticalStrut(h). Note: BoxLayout is unusual in that it must use a pane and not a frame as its container. An example of setting the BoxLayout to row alignment is:

p.setLayout(new BoxLayout(p,BoxLayout.X_AXIS));

GridLayout uses a simple row and column grid metaphor for layout. All components are of the same width and height and scale similarly when resized. The constructor format is:

setLayout(new GridLayout(rows, cols, x-spacing, y-spacing));

BorderLayout is used when you want to add components to a maximum of five sections arranged in North, South, East, West and Center positions. BorderLayout is the default manager for all content panes. If you place exactly five components in a container and use BorderLayout, each component fills one entire region. When the program runs, the compiler determines the exact size of each component based on the component's contents. When you resize a container that has BorderLayout, the regions also change in size. When you place less than 5 components in a container and use BorderLayout, any empty component regions disappear and the remaining components expand to fill the available space.

CardLayout presents widgets stacked similar to a deck of cards. It can be used to maintain a static pane of control buttons and another pane that is more dynamic in nature. A common use is a slideshow viewer where the controls are static and the picture frame is actually a set of card panes that are presented as buttons are pressed or a timer is called.

GridBagLayout allows precise placing and sizing of each widget. Use the properties: anchor, gridheight, gridwidth, gridx, gridy, fill, ipadx, ipady, weightx and weighty.

Source code for FlowGUI, BoxGUI, GridGUI, BorderGUI, GridBoxGUI and CardLayout examples using MVC is available. Compile each demo and note how the scaling on resize works.

Layered Design

All but the most simple of interfaces use nested layers of panes, often using several layout managers. As an example of a layered design, here is the code for a two column layout. The left column is a set of input selections. The right column is a set of 'go' buttons. A two column GridLayout is not used as it assumes both columns and rows will be equal sized. Instead we split the screen with a BorderLayout and then use two single column GridLayouts. The left GridLayout is further split using FlowLayout for captioning. Cut and paste the following to a file called Layer.java, compile and run to view the effect. Note: The MVC model is used to isolate view coding from action coding.

NOTE: The buttons created by this demo do not provide their implied functions but simply end the program. To fully implement button action, use either basic event listeners with a nested if constructs or advanced event listeners.



JR's HomePage | Comments [jatutord.htm:2009 05 23]