Components

Contents:
Component
Labels
Buttons
Simple Calculator
Canvas
Creating Your Own Component
Cursor

This chapter introduces the generic graphical widget used within the AWT package, Component, along with a trio of specific components: Label, Button, and Canvas. It also covers the Cursor class, new to Java 1.1. (Cursor support was previously part of the Frame class.) Although many objects within AWT don't subclass Component, and though you will never create an instance of Component, anything that provides screen-based user interaction and relies on the system for its layout will be a child of Component. As a subclass of Component, each child inherits a common set of methods and an API for dealing with the different events (i.e., mouse click, keyboard input) that occur within your Java programs.

After discussing the methods in Component classes, this chapter goes into detail about two specific components, Label and Button. A Label is a widget that contains descriptive text, usually next to an input field. A Button is a basic mechanism that lets the user signal the desire to perform an action. You will learn about the Canvas object and how to use a Canvas to create your own component. Finally, we cover the Cursor class, which lets you change the cursor over a Component.

Before going into the mechanics of the Component class, it's necessary to say a little about the relationship between components and containers. A Container is also a component with the ability to contain other components. There are several different kinds of containers; they are discussed in Containers. To display a component, you have to put it in a container by calling the container's add() method. We often call the container that holds a component the component's parent ; likewise, we call the components a container holds its children. Certain operations are legal only if a component has a parent--that is, the component is in a container. Of course, since containers are components, containers can contain other containers, ad infinitum.

NOTE:

If you think some component is missing a method that should obviously be there, check the methods it inherits. For example, the Label class appears to lack a setFont() method. Obviously, labels ought to be able to change their fonts. The setFont() method really is there; it is inherited from the Component class, and therefore, not documented as part of the Label class. Even if you're familiar with object-oriented techniques, the need to work up a class hierarchy to find all of the class's methods can lead to confusion and frustration. While all Java objects inherit methods from other classes, the potential for confusion is worst with components, which inherit over a hundred methods from Component and may only have a few methods of their own.

Component

Every GUI-based program consists of a screen with a set of objects. With Java, these objects are called components. Some of the more frequently used components are buttons, text fields, and containers.

A container is a special component that allows you to group different components together within it. You will learn more about containers in the next chapter, but they are in fact just another kind of component. Also, some of the parameters and return types for the methods of Component have not been explained yet and have their own sections in future chapters.

Component Methods

Constants

Prior to Java 1.1, you could not subclass Component or Container. With the introduction of the LightweightPeer, you can now subclass either Component or Container. However, since you no longer have a native peer, you must rely on your container to provide a display area and other services that are normally provided by a full-fledged peer. Because you cannot rely on your peer to determine your alignment, the Component class now has five constants to indicate six possible alignment settings (one constant is used twice). The alignment constants designate where to position a lightweight component; their values range from 0.0 to 1.0. The lower the number, the closer the component will be placed to the origin (top left corner) of the space allotted to it.[1]

[1] As of Beta 3, these constants appear to be seldom used. The getAlignmentX() and getAlignmentY() methods return these values, but there are no setAlignment methods.

Variables Constructor

Prior to Java 1.1, there was no public or protected constructor for Component. Only package members were able to subclass Component directly. With the introduction of lightweight peers, components can exist without a native peer, so the constructor was made protected, allowing you to create your own Component subclasses.

Appearance Positioning/Sizing

Component provides a handful of methods for positioning and sizing objects. Most of these are used behind the scenes by the system. You will also need them if you create your own LayoutManager or need to move or size an object. All of these depend on support for the functionality from the true component's peer.

Painting

The only methods in this section that you call directly are the versions of repaint(). The paint() and update() methods are called by the system when the display area requires refreshing, such as when a user resizes a window. When your program changes the display you should call repaint() to trigger a call to update() and paint(). Otherwise, the system is responsible for updating the display.

Imaging

Background information about using images is discussed in Simple Graphics and Image Processing. The imageUpdate() method of Component is the sole method of the ImageObserver interface. Since images are loaded in a separate thread, this method is called whenever additional information about the image becomes available.

Peers State Procedures

These methods determine whether the component is ready to be displayed and can be seen by the user. The first requirement is that it be valid--that is, whether the system knows its size, and (in the case of a container) whether the layout manager is aware of all its parts and has placed them as requested. A component becomes invalid if the size has changed since it was last displayed. If the component is a container, it becomes invalid when one of the components contained within it becomes invalid.

Next, the component must be visible--a possibly confusing term, because components can be considered "visible" without being seen by the user. Frames (because they have their own top-level windows) are not visible until you request that they be shown, but other components are visible as soon as you create them.

Finally, to be seen, a component must be showing. You show a component by adding it to its container. For something to be showing, it must be visible and be in a container that is visible and showing.

A subsidiary aspect of state is the enabled quality, which determines whether a component can accept input.

Table 5.1 compares possible return values from isVisible() and isShowing(). The first two entries are for objects that have their own Window. These will always return the same values for isVisible() and isShowing(). The next three are for Component objects that exist within a Window, Panel, or Applet. The visible setting is always initially true. However, the showing setting is not true until the object is actually drawn. The last case shows another possibility. If the component exists within an invisible Container, the component will be visible but will not be shown.

isVisible vs. isShowing
Happenings isVisible isShowing
Frame created false false
Frame f = new Frame ()
Frame showing true true
f.show ()
Component created true false
Button b= new Button ("Help")
Button added to screen in init() true false
add (b)
Container laid out with Button in it true true
Button within Panel that is not visible true false
Focus

Although there was some support for managing input focus in version 1.0, 1.1 improved on this greatly by including support for Tab and Shift+Tab to move input focus to the next or previous component, and by being more consistent across different platforms. This support is provided by the package-private class FocusManager.

Miscellaneous methods

Component Events

Events covers event handling in detail. This section summarizes what Component does for the different event-related methods.

With the Java 1.0 event model, many methods return true to indicate that the program has handled the event and false to indicate that the event was not handled (or only partially handled); when false is returned, the system passes the event up to the parent container. Thus, it is good form to return true only when you have fully handled the event, and no further processing is necessary.

With the Java 1.1 event model, you register a listener for a specific event type. When that type of event happens, the listener is notified. Unlike the 1.0 model, you do not need to override any methods of Component to handle the event. Controllers

The Java 1.0 event model controllers are deliverEvent(), postEvent(), and handleEvent(). With 1.1, the controller is a method named dispatchEvent().

public boolean handleEvent(Event event) {
 switch (event.id) {
 case Event.MOUSE_ENTER: return mouseEnter (event, event.x, event.y); case Event.MOUSE_EXIT: return mouseExit (event, event.x, event.y); case Event.MOUSE_MOVE: return mouseMove (event, event.x, event.y); case Event.MOUSE_DOWN: return mouseDown (event, event.x, event.y); case Event.MOUSE_DRAG: return mouseDrag (event, event.x, event.y); case Event.MOUSE_UP: return mouseUp (event, event.x, event.y); case Event.KEY_PRESS: case Event.KEY_ACTION: return keyDown (event, event.key); case Event.KEY_RELEASE: case Event.KEY_ACTION_RELEASE: return keyUp (event, event.key); case Event.ACTION_EVENT: return action (event, event.arg); case Event.GOT_FOCUS: return gotFocus (event, event.arg); case Event.LOST_FOCUS: return lostFocus (event, event.arg);
}
return false;
}
Action Keyboard Mouse

NOTE:

Early releases of Java (1.0.2 and earlier) propagated only mouse events from Canvas and Container objects. However, Netscape Navigator seems to have jumped the gun and corrected the situation with their 3.0 release, which is based on Java release 1.0.2.1. Until other Java releases catch up, use these events with care. For more information on platform dependencies, see Appendix C, Platform-Specific Event Handling.

Focus

Focus events indicate whether a component can get keyboard input. Not all components can get focus (e.g., Label cannot). Precisely which components can get the focus is platform specific.

Ordinarily, the item with the focus has a light gray rectangle around it, though the actual display depends on the platform and the component. Figure 5.1 displays the effect of focus for buttons in Windows.

Figure 5.1: Focused and UnFocused buttons

[Graphic: Figure 5-1]

NOTE:

Early releases of Java (1.0.2 and earlier) do not propagate all focus events on all platforms. Java 1.1 seems to propagate them properly. For more information on platform dependencies, see Appendix C, Platform-Specific Event Handling.

Listeners and 1.1 Event Handling

With the 1.1 event model, you receive events by registering event listeners, which are told when the event happens. Components don't have to receive and handle their own events; you can cleanly separate the event-handling code from the user interface itself. This section covers the methods used to add and remove event listeners, which are part of the Component class. There is a pair of methods to add and remove listeners for each event type that is appropriate for a Component: ComponentEvent, FocusEvent, KeyEvent, MouseEvent, and MouseMotionEvent. Subclasses of Component may have additional event types and therefore will have additional methods for adding and removing listeners. For example, Button, List, MenuItem, and TextField each generate action events and therefore have methods to add and remove action listeners. These additional listeners are covered with their respective components.

Handling your own events

Under the 1.1 event model, it is still possible for components to receive their own events, simulating the old event mechanism. If you want to write components that process their own events but are also compatible with the new model, you can override processEvent() or one of its related methods. processEvent() is logically similar to handleEvent() in the old model; it receives all the component's events and sees that they are forwarded to the appropriate listeners. Therefore, by overriding processEvent(), you get access to every event the component generates. If you want only a specific type of event, you can override processComponentEvent(), processKeyEvent(), or one of the other event-specific methods.

However, there is one problem. In Java 1.1, events aren't normally generated if there are no listeners. Therefore, if you want to receive your own events without registering a listener, you should first enable event processing (by a call to enableEvent()) to make sure that the events you are interested in are generated.