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

Lesson 14.3 Component Features

New JFC Component Features

As you saw in the last lesson, each of the AWT components has a corresponding J-Component: Labels have JLabels, Buttons have JButtons, and so on. In this section, we'll look at both of these new J-Class components, along with some of the new things you can do with Swing. 

In Lesson 14.4, 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.

Before we start looking at JButtons and JLabels, however, let's look at two features that can work with almost all of the new Swing widgets--Borders and Icons.

Borders and Icons

In Java 1.1, it was difficult to add a border to a container--you had to subclass the component you wanted to add the border to, and then override the getInsets() method. Often, even when you did that, the peer-based design of Java 1 prevented your code from working like you wanted; you'd paint a nice border and the native peer object would come along and wipe it out.

Likewise, creating Labels or Buttons that used images was more trouble than you'd expect. If you tried to subclass the Button and Label classes, you might get your code working on one platform, but likely it would look different on each. If you wanted a true cross-platform solution, you had to create your image-buttons and image-labels from scratch, extending the Canvas or Component class.

In Java 2, that's all changed; both the JLabel and JButton class will let you change their borders and will display images without any additional work on your part. In addition, the work of creating images has gotten much easier [at least in applications] through the advent of the ImageIcon class.

Back to Top

ImageIcon

The ImageIcon class makes creating images easy by preloading the images automatically using MediaTracker. There are nine ImageIcon constructors, but they are all variations on these three, which you'll use most often:

ImageIcon(String filename);
ImageIcon(URL url);
ImageIcon(Image img);

The first constructor is definitely the easiest to use, at least in an application. Creating an ImageIcon is as easy as:

ImageIcon one = new ImageIcon("Car1.GIF");
ImageIcon two = new ImageIcon("images/Car2.GIF");

The first example loads the image from a file in the current directory, while the second loads the image from the images subdirectory, immediately beneath the current directory. Note the use of forward slashes, even on machines, such as Windows and Mac, which use different separators.

The second constructor requires you to create a URL object; that means you have to deal with the dreaded MalformedURLException nonsense, as well as try-catch. Here's an example:
import java.net.*; // For URL
...

URL u = null;
try
{
  u = new URL("http://csjava.occ.cccd.edu/occ_logo.gif");
}
catch (MalformedURLException me) { me.printStackTrace(); }

ImageIcon two = new ImageIcon(u);

Of course, you can make that considerably easier by writing a method that returns URL objects and handles the try-catch like this:
URL getURL(String s)
{
   URL u = null;
   try 
   {
      u = new URL(s);
   }
   catch (MalformedURLException me) 
   { me.printStackTrace(); }

   return u;
}

ImageIcon two = new ImageIcon(
  getURL("http://csjava.occ.cccd.edu/occ_logo.gif"));

The third ImageIcon constructor, which requires an Image argument, is primarily useful inside applets, where you can only load an image from the machine that serves the applet. In fact, it is the only way to load create an ImageIcon inside an applet.

Here's an example:

// Inside an applet so getImage() works
ImageIcon two = new ImageIcon(
    getImage(getDocumentBase(), "Car1.GIF"));

In the next section, I'll show you how to use ImageIcons inside JButtons and JLabels; before we go on, however, let's take a look at borders.

Back to Top

Borders and the BorderFactory

The BorderFactory is a Swing class that knows how to create several different types of Border objects. Once you've created a Border object, you can apply it to almost every Swing component using the JComponent.setBorder() method.

Here are the basic set of Borders available from the BorderFactory:

  • LineBorder: A single line. You can specify color and thickness.
  • BevelBorder: A 3D border that can be raised or lowered.
  • EtchedBorder: A 3D sunken line border. You can also specify colors.
  • TitledBorder: A line border with a title. Several varieties.
  • EmptyBorder: Useful when all you want is some space
  • MatteBorder: A solid color or tiled-image border
  • CompoundBorder: Any combination of the above.

Each of the methods inside the BorderFactory class is a static method. Here's the code you'd use to place a title around each area of the WidgetOne application, which is presented in the next section.

Border b1 = BorderFactory.createTitledBorder("JButtons");
Border b2 = BorderFactory.createTitledBorder("JLabels");
Border b3 = BorderFactory.createLoweredBevelBorder();
p1.setBorder(b1);
p2.setBorder(b2);
p3.setBorder(b3);

JButtons

The JButton class works much like the Button class, as you saw in the last lesson. Instead of just two constructors, like Button, however, the JButton class has four:

  • JButton(): the default constructor
  • JButton(Icon): displays an image
  • JButton(String): displays text
  • JButton(Icon, String): displays both text and an image

Here's a fragment of code from WidgetOne.java that creates three JButton objects, using different constructors: [Click here to download WidgetOne.java]

JButton btn1 = new JButton(new ImageIcon("Car1.GIF"));
JButton btn2 = new JButton("Plain Text");
JButton btn3 = new JButton("Car2.GIF",
                   new ImageIcon("Car2.GIF"));

Here's what these three JButtons look like:

Image: The WidgetOne application - creating 3 buttons
Back to Top

Mnemonics and ToolTips

JButtons automatically handle mnemonic key identifiers ["shortcuts" or "hot-keys" for us mere mortals], as well as tool-tips.

Use the setMnemonic() method to assign an Alt+Key keyboard shortcut to a particular button. If the button contains text, then the shortcut character will be underlined. 

Here's an example that assigns the keyboard shortcut Alt+P to the plain text JButton in WidgetOne. When the button is displayed, the 'P' in "Plain Text" is underlined:

btn2.setMnemonic('P');

You can use keyboard shortcuts that don't generate a character codes by using the virtual key constants in the KeyEvent class. [Make sure you include java.awt.event.* if you do this.]

Here is an example that uses the Alt+F1 function key to trigger the JButton named btn1:

btn1.setMnemonic(KeyEvent.VK_F1);

Using "tool-tips"--the small help message that appears when your mouse hovers over a component for a few seconds--is even easier than setting a keyboard shortcut. You just call the method setToolTipText(), and it works. 

Here's an example:

btn1.setToolTipText("Click here to order a blue car");

The tool-tip will even display the keyboard shortcut [if assigned] when it pops up. [Note, however, that it seems to have some problem correctly identifying function-key shortcuts.]

This is what the btn1 tool-tip looks like for the WidgetOne application. [Note the problem with the mnemonic, which should be Alt+F1]:

Image:The WidgetOne application. Showing the tool-tip for button 1
Back to Top

ActionEvent and ActionCommand

JButtons use the same Java 1.1 event model that AWT Buttons use. Note that, unlike Button objects, JButtons are not compatible with the Java 1.0 event model; a JButton will never call your action() method.

If you want to use a single actionPerformed() method for several JButtons, you have to be able to identify which JButton was clicked. Here are three ways to do that:

  • Make your JButtons fields and explicitly test the identity of each JButton using ActionEvent.getSource(). Unfortunately, this leads to a proliferation of UI fields cluttering up your classes.
  • Test the label stored on the face of the JButton. Unfortunately, this doesn't work with iconic buttons, and your code breaks when you correct the spelling on the face of your JButton, but forget to update your actionPerformed() method.
  • You can assign a specific "action" String to each JButton, that is separate from the text that appears on the surface of the button. The nice thing about this solution--which is much better than the previous two--is that you can use the same action command for menu selections as well as for JButtons; that way you only have to make one test inside your actionPerformed() method.

To set the action command for a component, use the setActionCommand() method. When it comes time to test the component, you use the ActionEvent's getActionCommand() method to retrieve it. Here's an example:

btn1.setActionCommand("cut");
btn2.setActionCommand("copy");
btn3.setActionCommand("paste");
...
public void actionPerformed(ActionEvent ae)
{
  System.out.println(
    "ActionCommand = "+ae.getActionCommand());
}

JLabels

The JLabel class has two more constructors than the JButton class, because you can align the text in a JLabel, but not in a JButton. Here are the JLabel constructors:

  • JLabel(): the default constructor
  • JLabel(Icon): displays an image
  • JLabel(Icon, int): displays an image with a specific alignment.
  • JLabel(String): displays text
  • JLabel(String, Icon, int): displays text and an image with alignment
  • JLabel(String, int): displays text with alignment 

Here is some code [from WidgetOne.java, again] to create three different JLabels, centered in a JPanel using GridLayout:

// Create border around JLabels panel
JPanel p3 = new JPanel();
Border b3 = BorderFactory.createTitledBorder("JLabels");
p3.setBorder( b3 );
p3.setLayout(new GridLayout(1,3,5,5));
add(p3);

// Create three JLabels
JLabel lbl1 = new JLabel(new ImageIcon("Car3.GIF"));
JLabel lbl2 = new JLabel("A Plain Label", JLabel.CENTER);
JLabel lbl3 = new JLabel("Car4.GIF",
                  new ImageIcon("Car4.GIF"),
                  JLabel.RIGHT);

Here's what the JLabels look like when you run this code:

Image: WidgetOne - constructing three JLabel objects
Back to Top

Label Borders

In the sample, you can see how a TitledBorder is placed around all three JLabels. You can also put borders around individual components as well. This is not done much with JButtons because they have their own borders already. It is very common with JLabels, however.

Here's some code that shows how to place a red LineBorder around the left-hand JLabel, a MatteBorder using a tiled image around the center JLabel, and a MatteBorder using a solid color, but unequal border widths around the right-hand JLabel.
// Add different Borders to the JLabels
lbl1.setBorder(
  BorderFactory.createLineBorder(Color.red, 5));

lbl2.setBorder(
  BorderFactory.createMatteBorder(16, 12, 16, 12,
    new ImageIcon("bullet.gif")));
lbl3.setBorder(
  BorderFactory.createMatteBorder(1,1,5,5, 
    Color.darkGray));

Here's what these borders look like when the program runs:

Image: Adding borders to the JLabels in WidgetOne

Label Alignment

The JLabel class has the ability to specify both the horizontal and vertical alignment of the label contents. In addition, you can specify the horizontal and vertical position of the text, and the spacing that should appear between the text and the image [if any].

Let's see how this works. We'll start by specifying the contents of the  left-hand JLabel [the yellow car] should be aligned at the bottom of the JLabel and to the left. Do that with the setHorizontalAlignment() and setVerticalAlignment() methods like this:

lbl1.setHorizontalAlignment(JLabel.LEFT);
lbl1.setVerticalAlignment(JLabel.BOTTOM);

For the right-hand car, we'll align the image at the top and center of the JLabel, using setVerticalAlignment() and setHorizontalAlignment(). Then, we'll align the text separately by using the setHorizontalTextPosition() and setVerticalTextPosition() methods.

Finally, we'll set the spacing between the text and the image on the JLabel by using the setTextIconGap() method.

Here's the finished code:
// Set the position of icon 3
lbl3.setVerticalAlignment(JLabel.TOP);
lbl3.setVerticalTextPosition(JLabel.BOTTOM);
lbl3.setHorizontalAlignment(JLabel.CENTER);
lbl3.setHorizontalTextPosition(JLabel.CENTER);
lbl3.setIconTextGap(10);

And here's the finished WidgetOne application:

Image: The completed WidgetOne application

Something to Talk About

In this section, you learned about the JLabel and JButton class that replace the AWT Label and Button class. You also learned about the ImageIcon and BorderFactory classes which allow you to add images and borders to Swing components.

Read through the documentation on the BorderFactory class, and tell us how you could create a colored border [like the one shown around the yellow car] combined with an etched border [like the one shown around the buttons] inside of it.

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