Java Programming   Java Programming
 |Sofia Home | Content Gallery |
Home
Syllabus
Schedule
Lessons
Assignments
Resources

Lesson 14.2 JFC Basics

Swing Programming Basics

This lesson will show you how to build applications and applets that use the JFC.

In Lesson 14.3, you'll learn how to use the Swing components designed to replace existing AWT components such as buttons, labels, and edit controls, and how to use the new Swing features such as image icons and borders, which are available in the new Swing components.

In Lesson 14.4, "New Swing Components", you'll learn about some new Swing components that don't replace existing components. If you want a quick peek, you can take a look at Sun's pictoral JFC component gallery

Swing and the JFC

Since I first started programming in Java, with the pre 1.0 beta, it has gotten much much larger. For instance:

  • In the Java 1.0 API, there were 8 packages, about 200 classes, and nearly 2,000 members. [Members include methods, constructors, and public fields]. That's quite a bit to remember, but it can be done.
  • In the Java 1.1 API, there were 23 packages [almost 3X], about 500 classes, and roughly 5,000 members. Mastering that much material is much more difficult, and requires good organization.
  • In the Java 2 API, there are 60 packages [almost 3X again], about 1,700 classes, and over 20,000 members.
Fortunately, you don't have to master all 1,700 classes to understand enough to be productive. Like all good learning, you can master the JFC by building on what you already know. In these next two sections we'll do that by:
  1. Learning the basic structure of an applet and an application.
  2. Learning to use the AWT "replacement" components. 
  3. Learning about the new components that are not available in the AWT.

A Little JFC Background

For every component in the AWT, such as Button or Label, there is a new JFC component that starts with J: the JButton and the JLabel, for instance. This continuity allows you to build on what you already know, while adding new functionality.

In addition to these "replacement" components, there are also new components available that are not available in the AWT. These include the JSlider class, the JProgressBar class, and the JToolBar class, which you'll study in the Lesson 14.4, as well as more complex and sophisticated components such as trees, grids, and editors.

Back to Top

Lightweight-Heavyweight

You might wonder why the JFC didn't simply improve the existing Button class instead of adding a whole new class. There is an important reason for this, and it underlies the basic difference between the AWT and the JFC:
  • In the AWT, all components are created by the underlying operating system. These are called "heavyweight" components.
  • In the JFC, all components, except for JFrame and a few others, are lightweight components--they don't involve the operating-system created "peers" that underly the AWT.
Two important consequences follow from this underlying difference:
  • In the AWT, the user interface will take on the look of the operating system that the program is running on. The same Java program will look different when run on different systems. With the JFC, that's not true; a JFC program can look the same on the Mac, Solaris, and Windows.
  • JFC and AWT components don't "mix and match" very well. Because of their different underlying architectures, you should try and use only JFC components or only AWT components; not half-and-half. That's why the Button class wasn't simply improved; it's because the JFC is a fundamentally different animal.
This doesn't mean, however, that the AWT has gone away. In fact, all of the new Swing components are derived from java.awt.Container, [which is, itself, derived from java.awt.Component], so all of the time you've spent learning how to use Java Component objects is not wasted at all. In addition, all of the Graphics methods in the AWT have been retained, and many of them have been enhanced.

Let's start by learning how to build a Java applet that uses Swing. To compile and run these programs you must have either the Java 2 Software Development Kit installed, or have installed the JFC classes for Java 1.1, as described in the previous lesson. 

[You should follow along as we walk through these examples, but you don't have to compile and run the examples for the class; that's not required.]

Back to Top

How to Build a JFC Applet

Let's start with the simplest possible applet, which I'll name J2Applet1. The J2Applet1 program will simple draw several ovals inside its paint() method.

You can click here to download J2Applet1.java. You will need to create an HTML file to display the program in appletviewer. 

The import Statements

Start your applet with the import statements like this:

//  J2Applet1.java
//  A first Java 2 Applet
//  Orange Coast College
//  CS 170 Online
//  Stephen Gilbert

import java.awt.*;    // Graphics, Color, etc.
import javax.swing.*; // JApplet

Notice these differences:

  • You still import the java.awt package which you'll need for the Graphics class and the Color class.
  • Most of the JFC classes are in the javax.swing package, which you'll import in almost every JFC program. The javax denotes a "standard extension", that is, an extension that is generally present in every distribution of the platform. Of course since no one, except Sun, has yet delivered a Java 2 distribution, it's hard to tell how much reliance to place on that assurance.
  • You don't need the java.awt.applet.*; import statement. The Java 2 applet class is part of the javax.swing package.

Basic Structure

The basic structure of your Java 2 applet looks like this:

//  J2Applet1.java
//  A first Java 2 Applet
//  Orange Coast College
//  CS 170 Online
//  Stephen Gilbert

import java.awt.*;    // Graphics, Color, etc.
import javax.swing.*; // JApplet

public class J2Applet1 extends JApplet
{

}

The only difference here--from a Java 1 applet--is that the Applet class has been replaced by a JFC class named JApplet.

Back to Top

The paint() Method

Adding a paint() method to your applet makes it look like this:

//  J2Applet1.java
//  A first Java 2 Applet
//  Orange Coast College
//  CS 170 Online
//  Stephen Gilbert

import java.awt.*;    // Graphics, Color, etc.
import javax.swing.*; // JApplet

public class J2Applet1 extends JApplet
{
  public void paint(Graphics g)
  {
    int width  = getSize().width;
    int height = getSize().height;

    g.setColor(Color.red);
    g.fillOval(0, 0, width, height);
    g.setColor(Color.blue);
    g.drawOval(width/4, 0, width/2, height);
    g.setColor(Color.green);
    g.drawOval(0, height/4, width, height/2);
  }
}

As you can see by examining the code above, the paint() method is written exactly like it would if this were a Java 1.1 Applet instead of a Java 1.2 JApplet. If you look at the screenshot shown here, you'll see that it doesn't look any different when it runs, either.

Given that, you might wonder what difference exists between JApplets and Applets, besides a different first initial. To discover that, we'll have to look at a modification of J2Applet1 named J2Applet2.

Image: The J2Applet1 program running in appletviewer

Adding a JButton

The JButton class is the JFC replacement for the AWT Button, just as the JApplet is a replacement form the Applet. Let's create and add a JButton to the surface of our applet. To do so, follow these instructions.
  • Copy J2Applet1.java to J2Applet2.java
  • Change the name of the class to J2Applet2 from J2Applet1.
  • Add the following init() method to the applet.
  • public void init()
    {
      JButton b = new JButton("Hi There");
      add(b);
    }

When you compile and run your program, this is what you'll see:

Image:Running the J2Applet2 without using getContentPane()

and your console will give the following error message:

java.lang.Error: 
Do not use J2Applet2.add() use J2Applet2.getContentPane().add()
instead

What is that all about?

Back to Top

The ContentPane() Pain

The biggest difference between Applets and JApplets, or between Frames and JFrames for that matter, is that you cannot add components directly to the surface of a JApplet or a JFrame. That's because there is already something occupying the surface of a JApplet and JFrame.

Actually, there are several somethings: there is a RootPane, a GlassPane, and a ContentPane. Instead of adding your components to your JApplet, you have to do this:

  1. Create a Container object [let's call it c]
  2. Initialize your Container object by calling getContentPane();
  3. Add all of your components to the object c.
To fix J2Applet2, change the init() method so that it looks like this:

public void init()
{
  Container c = getContentPane();
  JButton b = new JButton("Hi There");
  c.add(b);
}

Now compile and run your program, and you'll find that it doesn't crash like before.

Unfortunately, it looks like it doesn't work either. At first glance, there's no JButton in evidence. 

Appearances can be deceiving, however. Poke at the applet for a second with your mouse, and see what pops up.

It looks like we have a JButton after all, but now the picture's disappeared. You can make the picture reappear, (and the JButton disappear), if you like, by simply resizing the appletviewer window:

Voila! No more JButton. While this might seem kind of arbitrary, it really illustrates the three rules you'll have to follow every time you write a program with Swing.

Image: The J2Applet2 program [2nd version -- JButton but no image]

The Three Commandments

Here are the rules you'll have to follow whenever you write an application or an applet using the Java Foundation Classes:
  1. Always use getContentPane() to return a reference to your applet's main window. Add your components to the ContentPane instead of to the applet or frame.
  2. Always set a layout manager on the ContentPane if you want something other than BorderLayout. Unlike the Applet class, the JApplet class ContentPane does not default to FlowLayout. [That's why the JButton is so big when it makes its appearance in J2Applet2.]
  3. Do not paint directly on the surface of an applet or application (as we've been doing here). Instead, create a subclass of the JPanel class, and override its paintComponent() method--which takes the same arguments as paint(). Make sure, as well, that you always call super.paintComponent() from any paintComponent() method you override.
To fix J2Applet2, then, you need to:
  1. Create a subclass of JPanel [let's call it PaintPanel] that we can paint onto. We'll move our painting code from JApplet.paint() to the PaintPanel's paintComponent() method.
  2. Create an instance of PaintPanel and add our JButton to it.
  3. Add our PaintPanel object to the JApplet's ContentPane.

Here's what the completed J2Applet2 program looks like once you've made those changes.

You can now resize and move the applet window and the JButton never gets lost. That's because each component is responsible for painting its own space.

[Click here to download J2Applet2.java]

Image: The J2Applet2 program [3nd version -- JButton and image]

How to build an application Everything that you just learned about applets also applies to applications, with a couple additional caveats as well. 

Here's an overview:

  1. Your applications should use the JFrame class instead of the Frame class.
  2. You should not paint on, add items to, or set the layout manager for your JFrame. Instead, you should use the JFrame's ContentPane.
  3. You should add a WindowListener, just as you did for the Frame class to stop your application when its main window is closed. 
JFrame.setDefaultCloseOperation()
The JFrame class has a method, setDefaultCloseOperation() that allows you to specify what happens when a window is closed, without mucking around with WindowListener

According to the documents, you can specify:

  • DO_NOTHING_ON_CLOSE
  • HIDE_ON_CLOSE
  • DISPOSE_ON_CLOSE
Unfortunately, none of these choices stop your program if it is running. In JDK 1.3, you can specify EXIT_ON_CLOSE. For earlier versions you have to add a WindowListener, override the windowClosing() method, and call System.exit() yourself.
Back to Top

The GApp Generic Application

Since you have to repeat these same operations in every application, you may want to put them all into a class, and use the class as the basis for every application you build. 

The GApp class is a basic Java 2 application class that does just that. [Click here to download GApp.java.]
// GApp - A generic Java Application

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GApp extends JFrame
{
  public GApp(String title, Container p)
  {
    super(title);

    Container c = getContentPane();
    c.add(p);
    pack();

    addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent we)
      {
        System.exit(0);
      }
    });
  }
}

To use GApp, you:

  1. Create a new class as a subclass of Container. [Most of the time, you'll use JPanel.] This will be the "content" of your application.
  2. Add a main() method to your new class where you create an instance of your application, and an instance of GApp. In the main() method, you size and show() the GApp application window to fit your needs. 
Here's an example that shows how GApp works.

A FirstApp Example

First, we'll define a new application based upon JPanel like this:

// A first application that makes use of GApp
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FirstApp extends JPanel
{
  private JLabel  lbl = new JLabel("Hi there");
  private JButton btn = new JButton("Hide it");

  public FirstApp()
  {
    btn.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent ae)
      {
        if (lbl.isVisible())
        {
          lbl.setVisible(false);
          btn.setLabel("Show it");
        }
        else
        {
          lbl.setVisible(true);
          btn.setLabel("Hide it");
        }
      }
    });
    add(lbl);
    add(btn);
  }

  // The main() method will go here
}


The FirstApp class:
  • Has a JLabel and a JButton
  • An anonymous ActionListener, called whenever the JButton is pressed.
  • Hides the JLabel if it is visible and makes it visible if it is hidden. 
  • Changes the text on the JButton to reflect the actual state of the JLabel.
To use FirstApp, add a main() method like this:

public static void main(String[] args)
{
  FirstApp fa = new FirstApp();
  GApp app = new GApp("The First App", fa);
  app.setSize(250, 100);
  app.show();
}

The FirstApp main() method:
  1. Creates an instance of FirstApp named fa
  2. Creates an instance of GApp named app, passing a String to appear in the title bar, and a Container [the instance of FirstApp, in this case] to be added to the application's content pane.
  3. Sets the size of the application to 250 by 100
  4. Displays the application.

Here's what FirstApp looks like when it runs. To try the application yourself, click here to download GApp.java and click here to download FirstApp.java. Place both files in the same directory and compile and run.

Image: Running the FirstApp application

How to change the look and feel

Changing the "look and feel" of your application is not really difficult, but it's not really all that useful either. Part of the problem is that there are only four built-in PLAF [Pluggable Look and Feel] modules supplied with Java: 

  • Windows
  • Mac
  • Motif
  • Java [or Metal] 
The second part of the problem is that two of those--the Mac and the Windows L&F--only work on their respective platforms. If you try to use the Windows L&F on any machine where Windows is not the underlying O/S or the Mac L&F on any machine other than a Mac, it doesn't work. [This is for legal, not technical reasons.] 

This kind of defeats the whole purpose of PLAF. Until there is some kind of market in different "themes" or "skins", [kind of like the Enlightenment/KDE themes under Linux], I don't see this being really useful.

Here are the steps, however, if you want to look into it:

Step 1: Select a L&F Class

Use some code like this:

String lfn = name_of_class_here

The four built in classes are:

  • "javax.swing.plaf.metal.MetalLookAndFeel" 
  • "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" 
  • "com.sun.java.swing.plaf.motif.MotifLookAndFeel" 
  • "javax.swing.plaf.mac.MacLookAndFeel" 
Step 2: Set the L&F
Do this by calling the static UIManager.setLookAndFeel() method, passing the name of the String you selected in Step 1. 

This method seems to throw all sorts of exceptions, so you'll need to put it in a try-catch block, and you'll probably want to catch Exception, unless you're fond of writing several different catch blocks.

Step 3: Update the UI
Do this by calling the SwingUtilities.updateComponentTreeUI() method, passing in a reference to the top level Frame in your application. 

This causes the Frame to recursively change the UI used for each of the components it contains. Since the components have different sizes in each of the L&F classes, you may want to follow the updateComponentTreeUI() call with a pack() to tell the Frame to re-layout each of the components as well.

Back to Top

The PLAFApp Example

The PLAFApp program is a modification of FirstApp that adds three additional buttons: one for the Windows L&F, one for the Motif L&F, and one for the Metal [Java 2] L&F. When you press one of the buttons, the UI is updated.

Here's what the PLAFApp program looks like when it runs:

Image: The PLAFApp program with the Java [Metal] Look and Feel
Image: The PLAFApp program with the Motif look and feel
Image: The PLAFApp using the Windows look and fell

Click here to download PLAFApp.java.

Something to Talk About

In this section, you learned how to create a Swing applet using the JApplet class and a Swing application using the JFrame class. You also learned about Java's support for Pluggable Look and Feel, or PLAF.

Tell us about what you learned:

  1. What do you think about the idea of PLAF? 
  2. Do you think it's useful? 
  3. Do you think it's workable? 
  4. Do you think that MS and Apple will allow their L&F to be freely used? 

Please continue to the next section of this lesson.

 

Back to Top

 

Content Developed by Stephen Gilbert, Licensed under a Creative Commons License
Published by the Sofia Open Content Initiative
© 2004 Foothill-De Anza Community College District &The William and Flora Hewlett Foundation