[ Team LiB ] Previous Section Next Section

11.5 A Complete GUI

We've looked separately at components, containers, layout management, and event handling, so now it is time to tie these pieces together and add the additional details required to create a complete graphical user interface. Example 11-15 lists ScribbleApp.java, a simple paint-style application, pictured in Figure 11-13.

Figure 11-13. The ScribbleApp application

This application relies on the scribbling capabilities of the ScribblePane class of Example 11-13. It places a ScribblePane instance within a JFrame container to create the main application window and then adds a JMenuBar and two JToolBar components to allow the user to control the application. ScribbleApp uses a JColorChooser to let the user select a drawing color and a JOptionPane to display a confirmation dialog when the user asks to quit. You should pay particular attention to how these five Swing components are used; most full-featured applications use them in similar ways. Note that Example 11-15 is a complete application; it is designed to be run standalone, not to be viewed using the ShowBean program. However, the ScribbleApp class is designed as a subclass of JFrame, so that other applications can instantiate ScribbleApp windows of their own if they so choose.

This example also introduces the javax.swing.Action interface, which is a subinterface of java.awt.event.ActionListener. Any Action object can be used as an ActionListener to respond to an ActionEvent generated by a component. What the Action interface adds to the ActionListener interface is the ability to associate arbitrary properties with an Action object. The Action interface also defines standard property names that can specify the name, icon, and description of the action performed by the listener. Action objects are particularly convenient to use because they can be added directly to JMenu and JToolBar components; the components use the action name and/or icon to automatically create appropriate menu items or toolbar buttons to represent the action. (In Java 1.3, Action objects can also be passed directly to the constructor methods of components such as JButton.) Action objects can also be enabled or disabled. When an action is disabled, any component that has been created to represent it is also disabled, preventing the user from attempting to perform the action.

Example 11-15. ScribbleApp.java
package je3.gui;
import java.awt.*;          
import java.awt.event.*;    
import javax.swing.*;       
import javax.swing.border.*;

 * This JFrame subclass is a simple "paint" application.
public class ScribbleApp extends JFrame {
     * The main method instantiates an instance of the class, sets it size,
     * and makes it visible on the screen
    public static void main(String[  ] args) {
        // Set the look-and-feel for the application.  
        // LookAndFeelPrefs is defined elsewhere in this package.

        ScribbleApp scribble = new ScribbleApp( );

        // Handle window close requests
        scribble.addWindowListener(new WindowAdapter( ) {
                public void windowClosing(WindowEvent e) { System.exit(0); }

        // Set the window size and make it visible.
        scribble.setSize(500, 300);

    // The scribble application relies on the ScribblePane component developed
    // earlier.  This field holds the ScribblePane instance it uses.
    ScribblePane scribblePane;

     * This constructor creates the GUI for this application.
    public ScribbleApp( ) {
        super("Scribble");  // Call superclass constructor and set window title

        // All content of a JFrame (except for the menubar) goes in the
        // Frame's internal "content pane", not in the frame itself.
        // The same is true for JDialog and similar top-level containers.
        Container contentPane = this.getContentPane( );

        // Specify a layout manager for the content pane
        contentPane.setLayout(new BorderLayout( ));

        // Create the main scribble pane component, give it a border and
        // a background color, and add it to the content pane
        scribblePane = new ScribblePane( );
        scribblePane.setBorder(new BevelBorder(BevelBorder.LOWERED));
        contentPane.add(scribblePane, BorderLayout.CENTER);

        // Create a menubar and add it to this window.  Note that JFrame
        // handles menus specially and has a special method for adding them
        // outside of the content pane.
        JMenuBar menubar = new JMenuBar( );  // Create a menubar
        this.setJMenuBar(menubar);          // Display it in the JFrame

        // Create menus and add to the menubar
        JMenu filemenu = new JMenu("File");
        JMenu colormenu = new JMenu("Color");
        // Create some Action objects for use in the menus and toolbars.
        // An Action combines a menu title and/or icon with an ActionListener.
        // These Action classes are defined as inner classes below.
        Action clear = new ClearAction( );
        Action quit = new QuitAction( );
        Action black = new ColorAction(Color.black);
        Action red = new ColorAction(Color.red);
        Action blue = new ColorAction(Color.blue);
        Action select = new SelectColorAction( );

        // Populate the menus using Action objects

        // Add a submenu for selecting a look-and-feel.
        // The LookAndFeelPrefs utility class is later in the chapter.
        colormenu.add(new JSeparator( ));
                   new ActionListener( ) {
                      public void actionPerformed(ActionEvent e) {

        // Now create a toolbar, add actions to it, and add it to the
        // top of the frame (where it appears underneath the menubar)
        JToolBar toolbar = new JToolBar( );
        contentPane.add(toolbar, BorderLayout.NORTH);

        // Create another toolbar for use as a color palette, and add to 
        // the left side of the window.
        JToolBar palette = new JToolBar( );
        contentPane.add(palette, BorderLayout.WEST);

    /** This inner class defines the "clear" action that clears the scribble */
    class ClearAction extends AbstractAction {
        public ClearAction( ) {
            super("Clear");  // Specify the name of the action
        public void actionPerformed(ActionEvent e) { scribblePane.clear( ); }

    /** This inner class defines the "quit" action to quit the program */
    class QuitAction extends AbstractAction {
        public QuitAction( ) { super("Quit"); }
        public void actionPerformed(ActionEvent e) { 
            // Use JOptionPane to confirm that the user really wants to quit
            int response =
                JOptionPane.showConfirmDialog(ScribbleApp.this,"Really Quit?");
            if (response == JOptionPane.YES_OPTION) System.exit(0);

     * This inner class defines an Action that sets the current drawing color
     * of the ScribblePane2 component.  Note that actions of this type have
     * icons rather than labels
    class ColorAction extends AbstractAction {
        Color color;
        public ColorAction(Color color) {
            this.color = color;
            putValue(Action.SMALL_ICON, new ColorIcon(color)); // specify icon
        public void actionPerformed(ActionEvent e) {
            scribblePane.setForeground(color);  // Set current drawing color

     * This inner class implements Icon to draw a solid 16x16 block of the
     * specified color.  Most icons are instances of ImageIcon, but since
     * we're only using solid colors here, it is easier to implement this
     * custom Icon type
    static class ColorIcon implements Icon {
        Color color;
        public ColorIcon(Color color) { this.color = color; }
        // These two methods specify the size of the icon
        public int getIconHeight( ) { return 16; }
        public int getIconWidth( ) { return 16; }
        // This method draws the icon
        public void paintIcon(Component c, Graphics g, int x, int y) {
            g.fillRect(x, y, 16, 16);

     * This inner class defines an Action that uses JColorChooser to allow
     * the user to select a drawing color
    class SelectColorAction extends AbstractAction {
        public SelectColorAction( ) { super("Select Color..."); }
        public void actionPerformed(ActionEvent e) {
            Color color = JColorChooser.showDialog(ScribbleApp.this,
                                                   "Select Drawing Color",
                                                   scribblePane.getForeground( ));
            if (color != null) scribblePane.setForeground(color);
    [ Team LiB ] Previous Section Next Section