Writing GUI Applications in Java

Writing GUI Applications in Java

You can also write standalone GUI applications in Java. Unlike applets, you do not need a Web browser to run standalone applications. Also, these applications are not burdened by the strict security restrictions that are imposed on applets. Like other applications on your system, these Java applications can perform all operations. For example, standalone Java applications can read and write files and establish a TCP/IP connection with any Internet host.

Java GUI applications use the Swing GUI components that are part of Java 2 SDK. The applet example shown in the 'Writing a Simple Java Applet' section uses GUI components from the older Abstract Windowing Toolkit (AWT). The AWT includes a limited selection of components that may have been adequate for applets, but standalone GUI applications require many more user interface components, such as menu bars and tables, that the older AWT lacks. Swing extends AWT by adding an extensive collection of GUI components that are on a par with other popular windowing systems. Additionally, the Swing architecture supports what is known as pluggable look-and-feel that allows users to change the appearance of the user interface without having to restart the application.

Insider Insight

You will see the word plaf in the package name of Swing classes. That word is an acronym for 'pluggable look-and-feel.'

The next few sections briefly introduce the Swing GUI components, including a description of the modified Model-View-Controller (MVC) architecture of the Swing classes. Then a sample GUI application illustrates how to use many Swing GUI components. The sample GUI application shown is designed to run either as an applet or a standalone application.

An Overview of Swing

To understand the Swing class library, you need to know a bit about how Java's GUI classes came about. Java 1.0 came with the Abstract Windowing Toolkit, or AWT for short. AWT is a set of classes that allows you to build GUIs for applets and applications. AWT classes include the basic components such as buttons, labels, checkboxes, frames, text-input areas, scrollbars, and panels. AWT also provides graphics classes to handle drawing and image rendering.

Each of the GUI components in AWT has two parts: a Java class representing the component and a peer object that renders the component using the capabilities of the native windowing system on which the Java Virtual Machine is running. For example, in Microsoft Windows, AWT's Button component is drawn using a button from a Microsoft Windows library. This means that the button should look the same as other buttons in Microsoft Windows. On the other hand, the Button on a Macintosh will look like other buttons in the Macintosh user interface. The AWT components are known as heavyweight components because each component has a platform-specific implementation that is directly supported by a user interface component of the underlying windowing system. Typically, each component is rendered in a window from the windowing system.

The Swing components are a high-level collection of GUI components, implemented entirely in Java. (Swing was the name of the project that developed these components.) Swing renders components such as buttons and labels in a container such as a frame or a dialog box. The container is a heavyweight component that does rely on the underlying windowing system, but the components themselves do not make use of any user interface components from the underlying windowing system. The container provides the drawing area where various Swing components render themselves. Swing components are called lightweight because they do not have any representation in the underlying windowing system. For example, on a Microsoft Windows system, a Swing button does not use a Windows button. Instead, the button is drawn using graphics primitives such as lines and rectangles. This means that a Swing component should look the same on any system. In fact, as you will see later in this section, Swing allows you to change the look and feel of the user interface (UI) on the fly.

The following sections summarize the Swing classes, describe the modified Model-View-Controller architecture used in Swing and provide some Swing programming tips.

Java Foundation Classes (JFC) and Swing

Java Foundation Classes (JFC) is a collection of classes that provide everything you need to develop GUI applications. Swing happens to be a part of JFC, and JFC itself is incorporated into Java 2.

Secret

JFC includes the following major components:

Swing GUI components are lightweight GUI components for Java applications and applets. For the latest information on Swing classes and some programming tips, see The Swing Connection, an online newsletter at http://java.sun .com/products/jfc/tsc/. Swing does not replace AWT. Rather, Swing extends AWT by adding more class libraries that support all aspects of GUI programming.

Accessibility APIs allow developers to create GUI applications that can support people with disabilities such as limited sight or the inability to operate a mouse. For more information on the accessibility features, visit Sun's website at http:// java.sun.com/products/jfc/jaccess-1.2/doc/ and browse the online accessibility documentation.

Java 2D API is a set of classes for two-dimensional (2D) graphics and imaging. In particular, Java 2D API provides more control over the image rendering process. For more information on Java 2D API, visit the Java 2D API home page at http://java.sun.com/products/java-media/2D/. If you have JDK 1.2 installed, you can see what Java2D offers by running the Java2Demo program, which should be in the demo\jfc\Java2D subdirectory of the location where you installed JDK 1.2. (Use the command java Java2Demo to start the demo program.)

Drag and drop refers to the ability to cut and paste text and images between Java applications (as well as other applications running on your system). You can download the latest Drag and Drop specification from http://java.sun.com/ beans/glasgow/#draganddrop. In Java 2, the java.awt.dnd package includes the interfaces and classes for supporting drag-and-drop operations.

Swing happens to be the largest part of JFC. Originally, Swing was released as a separate class library that could be used with Java 1.1 class libraries. However, when Java 2 was officially released in December 1998, the Swing classes were included in it. The Swing classes are in various packages with names that begin with javax.swing.

JFC is essentially layered on the AWT, which, in turn, relies on the native windowing system (such as Microsoft Windows or Motif) to render the user interface on the display. Figure 26-4 illustrates the layered model of JFC. As the figure shows, the Swing components rely on parts of the AWT but not all of it. AWT components use the native windowing system to display output and receive user input from the mouse and keyboard. AWT components such as buttons, labels, panels, and frames are still available for use. The Accessibility APIs are closely tied to Swing components, but the Java2D API and Drag and Drop also rely on the native windowing system. Finally, Java GUI applications rely on the Swing components and they can also use the AWT components, if necessary.

Figure 26-4: The Layered Model of Java Foundation Classes (JFC).

Swing Classes

Because this book focuses on explaining Java programming through sample programs, you may not encounter all of the Swing classes here. Only the most commonly used Swing components show up in the various examples. However, it's useful to know the names of the various components, so you know what's available in Swing. Accordingly, Table 26-4 summarizes the Swing classes.

Table 26-4: Summary of Some Swing Component Classes

Class

Description

JApplet

Implements a Java applet capable of using Swing components. Any applet that uses Swing classes must be a subclass of JApplet.

JButton

Displays a button with some text and, optionally, an icon

JCheckBox

Displays a check box

JCheckBoxMenuItem

Displays a menu item that can be selected or deselected

JColorChooser

Displays a complex dialog box from which the user can select a color

JComboBox

Displays a combo box that includes a text field and a button to view a drop-down list of items

JComponent

Represents the superclass of most Swing classes

JDesktopPane

Implements a DesktopManager object that can be plugged into a JInternalFrame object

JDialog

Provides a container in which Swing components can be laid out to create custom dialog boxes

JEditorPane

Provides a text component to edit various types of content such as plaintext, HTML, and Rich Text Format (RTF)

JFileChooser

Displays a complex dialog box in which the user can browse through folders and select a file

Provides a container in which other Swing components can be laid out. Most standalone GUI applications use a JFrame as the top-level container for laying out other Swing components.

JInternalFrame

Implements a lightweight frame object that can be placed inside a JDesktopPane object

JLabel

Displays a label showing text or an image or both

JLayeredPane

Allows the display of multiple layered panes in a frame so that components can be overlaid

JList

Displays a list of objects (text or icons) from which the user can select one or more items

JMenu

Implements a drop-down menu that can be attached to a menu bar (the menu can show text or images or both)

JMenuBar

Implements a menu bar

JMenuItem

Implements a menu item that appears in a JMenu

JOptionPane

Displays a dialog box that prompts the user for input and then provides that input to the program

JPanel

Provides a lightweight container for arranging other components such as JButton, JLabel, and JComboBox

JPasswordField

Displays a text field in which the user can type a password (the characters typed by the user are not displayed)

JPopupMenu

Implements a pop-up menu

JProgressBar

Displays a progress bar that can be used to indicate the progress of an operation

JRadioButton

Implements a radio button that can display text or an image or both

JRadioButtonMenuItem

Implements a menu item that is part of a group of menu items, only one of which can be selected at any time

JRootPane

Creates an object with a glass pane, a layered pane, an optional menu bar, and a content pane

JScrollBar

Displays a scroll bar

JScrollPane

Implements a scrolled pane that can scroll objects placed inside the pane

JSeparator

Implements a separator that can be placed in a JMenu to separate one group of menu items from another

JSlider

Displays a slider bar from which the user can select a value

JSpinner

Displays a single line input field with a pair of tiny arrow buttons that enable the user to step through a sequence of values and select one (functionality is similar to that of JComboBox, but without a drop-down list)

JSplitPane

Implements a pane that can be split horizontally or vertically

JTabbedPane

Implements tabbed pane components that allow the user to view different pages by clicking on tabs (much like the tabs on file folders)

JTable

Implements a table that can display tabular data (ideal for displaying the results of database searches)

JTableHeader

Implements the column header part of a JTable (shares the same TableColumnModel with the JTable)

JTextArea

Implements a multiline text area that can be used to display read-only or editable text

JTextField

Provides a single-line text entry and editing area

JTextPane

Provides a text component that can be marked up with attributes that are represented graphically

JToggleButton

Implements a button that can display text or an image and that can be in one of two states (on or off)

JToolBar

Implements a toolbar that can either be attached to a frame or stand alone

JToolTip

Displays a short help message (attached to a component to provide help when the user moves the mouse onto that component)

JTree

Displays a set of hierarchical data in the form of a tree (similar to the directory structure in Windows Explorer)

JViewport

Displays a clipped view of a component (used by JScrollPane)

JWindow

Implements a container that can be displayed anywhere on the user's desktop (JWindow) does not have the title bar and window-management buttons associated with a JFrame)

The Model-View-Controller (MVC) Architecture and Swing

Swing components use a modified form of the Model-View-Controller (MVC) architecture. The classic MVC architecture of Smalltalk-80 breaks an application up into three separate layers:

Model-This is the application layer that implements the application's functionality. All application-specific code is in this layer.

View-This is the presentation layer that implements whatever is needed to present information from the application layer to the user. In a GUI, the view provides the windows.

Controller-This is the virtual terminal layer that handles the user's interactions with the application. This is a graphics library that presents a device-independent interface to the presentation layer.

Smalltalk's MVC architecture does an excellent job of separating the responsibilities of the objects in the system. The application-specific details are insulated from the user interface. Also, the user interface itself is broken down into two parts, with the presentation handled by the view and the user interaction (mouse and keyboard input) handled by the controller.

Each Smalltalk-80 application consists of a model and an associated view-controller pair. Figure 26-5 shows the usual interactions in Smalltalk-80's MVC architecture. The controller accepts the user's inputs and invokes the appropriate methods from the model to perform the task requested by the user. When the work is done, the method in the model sends messages to the view and controller. The view updates the display in response to this message, accessing the model for further information, if necessary. Thus, the model has a view and a controller, but it never directly accesses either of them. The view and controller, on the other hand, access the model's functions and data when necessary. The shaded box enclosing the view and controller in Figure 26-5 is meant to emphasize that in actual implementations, the view and controller are tightly coupled and typically treated as a single view-controller pair.

Secret

Swing uses a modified form of Smalltalk's MVC model. Each Swing component collapses the view and controller into a single user interface (UI) object, but retains the model as a separate entity. The model maintains state information such as the maximum, minimum, and current values of a scrollbar. The UI object handles the view and controller responsibilities by rendering the component and processing user input in the form of mouse and keyboard events. Additionally, Swing introduces a UI manager that handles the look-and-feel characteristics of each component. Figure 26-6 depicts the Model-UI object-UI manager architecture of Swing components.

Figure 26-6: The Modified MVC Architecture Used by Swing Components.

The UI manager controls the look-and-feel capabilities of a Swing component by communicating with the component's UI object, as shown in Figure 26-6.

If you think about look and feel, look refers to how the component appears on the display, and feel refers to how the component reacts to user inputs. In other words, look and feel are the responsibilities of the view and controller components of the MVC architecture. In each Swing component, the UI object handles the look and feel of the component. Because the class representing the component delegates the look-and-feel responsibilities to the UI object, that object is also referred to as the UI delegate.

You should remember that all Swing components use a separate model. Many simple components provide a default model that maintains the information you provide when you create the Swing component. For more complex Swing components, such as JTable, you have to provide a model that represents the tabular data and implements the interface expected by JTable.

Swing Programming Tips

When you use AWT components to create a user interface, you place AWT components such as buttons, labels, and checkboxes inside various AWT containers such as frames and panels. Typically, you end up with a hierarchical containment structure, grouping several components in a panel and then placing several panels inside another panel. You do not have to worry much about how the components paint themselves, because the AWT components are heavyweight components that rely on the underlying windowing system for rendering themselves.

The situation changes when you create a user interface with the lightweight Swing components. Swing components rely on Java code (as opposed to the underlying windowing system) to support the windowing features such as showing, hiding, moving, and resizing the components. The upshot is that you have to follow certain rules when constructing user interfaces with Swing components, and you have to follow a few key rules to ensure that the user interface is painted properly.

The first rule is to avoid mixing heavyweight and lightweight components when they may overlap. In other words, do not place an AWT component inside a Swing component and vice versa. When these two types of components overlap, they are not painted correctly. (If you must use both AWT and Swing components, the article at http://java.sun.com/ products/jfc/tsc/articles/mixing/index.html explains the rules for doing so.)

To use Swing components properly, you must start with one of the container classes in Swing. The most commonly used container classes are

JApplet for any applet that uses Swing components

JFrame for GUI applications that use Swing components

JDialog for dialog boxes that contain Swing components

These Swing containers use an appropriate heavyweight AWT component to create the display area where the lightweight Swing components can be arranged. Each of these containers has a content pane in which the rest of the components are placed. You must add other Swing components to the content pane. Call the getContentPane() method of the Swing container to get the content pane and then add the components to that pane. For example, here is how you would create a JFrame and add a JDesktopPane to that frame:

To add lightweight components to other lightweight components, such as JPanel, you simply need to call the add() method of the JPanel object.

Whenever you want to redraw any Swing component, call that component's repaint() method. As with AWT components, do not call paint() directly. For example, here's how the repaint() method of a JButton is called in a mouse listener to repaint the button as the user presses and releases the button:

When you define any class as a subclass of the Swing container classes (JApplet, JFrame, or JDialog) and override the paint() method, you must insert a call to super.paint(), as shown in the following example:

If you do not call super.paint(),the lightweight Swing components inside the container won't show up. This is a common problem with beginners to Swing programming.

Additionally, each Swing component breaks down the paint() processing into three distinct parts by calling three methods in the following sequence:

paintComponent() to draw this component

paintBorder() to draw this component's border

paintChildren() to draw this component's children

When you define any class as a subclass of a lightweight Swing component such as JPanel , you should override the paintComponent() method to perform any additional painting you want done. You should first call super.paintComponent() to properly draw the component, as shown in the following example:

Because Swing components draw themselves in a pane-a drawing area-provided by a container, Swing uses double buffering to avoid flickering when components are drawn. This means that the user interface is drawn in an off-screen buffer and then the off-screen image is copied to the screen. The doubleBuffered property of the JComponent class controls whether double buffering is enabled. By default, the doubleBuffered property is set to true. Although you can change this property by calling the setDoubleBuffered() method, you should leave double buffering enabled for all Swing components.

Displaying a Calendar Using Swing

This section presents ViewCal, a GUI application that displays a calendar for any selected month of a year. You can run ViewCal in two ways-as an applet inside an HTML document or as a standalone application by typing a command from a terminal window. By

studying this application, you will learn how to use a number of different Swing components. You will also learn how to convert an applet to an application by providing a static main() method that creates the frame necessary to display the calendar.

Listing 26-2 shows the ViewCal.java file that implements the ViewCal application. I describe the code in the section that follows the listing.

To compile and run ViewCal, type the following commands (I assume that you have the Java 2 SDK binary directory in the PATH environment variable):

javac ViewCal.java
java ViewCal

You should see the ViewCal application's window, as shown in Figure 26-7.

Figure 26-7: The ViewCal Application Displaying a Monthly Calendar.

Here is how you can interact with the ViewCal application's user interface:

Clicking on the drop-down menu (implemented using a Choice component) displays a list of months from which you can select a specific month. That month's calendar is then displayed.

You can type in a year (such as 2003) in the text field next to the drop-down menu for selecting a month. After you press Enter, ViewCal updates the monthly calendar to reflect the change in year.

Clicking the Prev and Next buttons change the calendar to the previous or next month.

The ViewCal application's user interface is organized using Panel objects, where each panel holds other components such as Label, Choice, and Button objects. Typically, each panel uses a GridLayout layout manager to arrange its components into rows and columns. The Panel objects, in turn, are placed in the applet using a BorderLayout layout manager.

To display the calendar, the application needs the day of the week for the first day of any month. The ViewCal application uses the GregorianCalendar class to create a Gregorian calendar. Then it calls the get(Calendar.DAY_OF_WEEK) method of the GregorianCalendar object to get the day of the week for a specific date.

Recall that ViewCal is designeds to be an applet as well as a standalone GUI application. Essentially, ViewCal is an applet first. That's why Listing 26-2 shows the ViewCal class as a subclass of JApplet (any applet that uses Swing components must be defined as a subclass of JApplet):

ViewCal also implements the ActionListener and ItemListener interfaces to handle mouse clicks on various GUI components. The ViewCal class implements these interfaces by providing the required actionPerformed() and itemStateChanged() methods.

As is typical in an applet, the init() method in Listing 26-2 lays out the user interface. Because ViewCal is a subclass of JApplet, you must add all GUI components to its content pane. The following lines of code from Listing 26-2 show how to get the content pane (which is a Container object) and set the layout manager for the content pane:

Later on, other high-level containers are added to the content pane named cp. For example, here is a line that adds a JPanel named pTop to the north position of the content pane (in the BorderLayout manager, the north position is the top edge of the container):

cp.add("North", pTop);

To enable ViewCal to run as a standalone application, you need a static main() method that prepares a frame and provides the context where the applet can run. The following lines show the main() method:

As these lines of code show, the main() method accepts an array of String objects as argument-these are the arguments that the user might have specified on the command line. For example, if the user were to start the application with a command such as java ViewCal arg1 arg2, the String array would contain arg1 and arg2. (Although ViewCal does not make any use of command-line arguments, the main() method must be declared with a String array for the arguments.)

The main() method defines a WindowListener of type WindowAdapter and provides the windowClosing() method, which handles a window closing event by exiting the application. The rest of main() creates a JFrame object that provides the window where ViewCal's user interface is displayed. The WindowListener object is associated with the JFrame so that the application exits when the user closes the JFrame.

Then main() creates an instance of ViewCal and initializes it by calling the init() method. It then adds the applet to the center of the JFrame (notice that you have to add the applet to the JFrame's content pane). Finally, the main() method makes the JFrame visible (this causes the ViewCal user interface to appear on the display screen).

Insider Insight

You can use the technique of providing a main() method to convert any applet to a standalone application. In the main() method, create a frame. Then, create an instance of the applet and call its init() method. Add that instance to the frame. You should also provide a WindowListener that handles the window closing event that occurs when the user closes the frame.