Section 7.3
Standard Components and Their Events


THIS SECTION DISCUSSES some of the GUI interface elements that are represented by subclasses of Component. It also introduces the event classes and listener interfaces associated with each type of component. The treatment here is very brief. I will give some examples of programming with these components in the next section.

The Component class itself defines many useful methods that can be used with components of any type. We've already used some of these in examples. Let comp be a variable that refers to any component. Then the following methods are available (among many others):

There is also an event type associated with components. Whenever a component is hidden, shown, moved, or resized, an event belonging to the class ComponentEvent is generated. These events are handled in the same way as the mouse and keyboard events that we saw in the previous chapter: If you want to listen for a ComponentEvent, you have to implement the ComponentListener interface. This interface defines four methods:

         public void componentResized(ComponentEvent evt);
         public void componentMoved(ComponentEvent evt);
         public void componentHidden(ComponentEvent evt);
         public void componentShown(ComponentEvent evt);

Once you have an object that implements this interface, you must register it with a component by calling the component's addComponentListener() method. The parameter, evt, contains a function, evt.getComponent(), that returns the Component that generated the event. From this interface, you are most likely to use the componentResized() method, which is useful when you want to take some action each time the size of a component is changed.


For the rest of this section, we'll look at subclasses of Component that represent common GUI components. Remember that using any component is a multi-step process. The component object must be created with a constructor. It must be added to a container. In many cases, a listener must be registered to respond to events from the component. And in some cases, a reference to the component must be saved in an instance variable so that the component can be manipulated by the program after it has been created.

Here is a simple applet that demonstrates several of the components discussed in this section. Across the top are a Choice menu, a Checkbox, and a TextField. The rest of the applet shows a large canvas with ScrollBars below and to the right. The scroll bars control the color of the display. If you type in the TextField and press return, the text you typed will be displayed on the canvas.

Sorry, but your browser
doesn't support Java.

Although this is a rather silly example, it does show how to create and use several types of components. You'll find the source code for this example in the file EventDemo.java.


The Button Class

An object of class Button is a push button. You've already seen buttons used in the previous chapter, but we can use a review of Buttons as a reminder of what's involved in using components, events, and listeners. (Some of the methods described here are new.)

Of course, Buttons also have all the general Component methods, such as setEnabled() and setFont(). The setEnabled() and setLabel() methods of a button are particularly useful for giving the user information about what is going on in the program. A disabled button is better than a button that gives an obnoxious error message such as "Sorry, you can't click on me now!"


The Label Class

Labels are certainly the simplest type of component. An object of type Label is just a single line of text. The text cannot be edited by the user, although it can be changed by your program. The constructor for a Label specifies the text to be displayed:

Label message = new Label("Hello World!");

There is another constructor that specifies where in the label the text is located, if there is extra space. The possible alignments are given by the constants Label.LEFT, Label.CENTER, and Label.RIGHT. For example,

Label message = new Label("Hello World!", Label.CENTER);

creates a label whose text is centered in the available space. You can change the text displayed in a label by calling the label's setText() method:

message.setText("Goodby World!");

Since the Label class is a subclass of Component, you can use methods such as setForeground() with labels. For example:

      Label message = New Label("Hello World!");
      message.setForeground(Color.red);   // display red text...
      message.setBackground(Color.black); //    on a black background...
      message.setFont(new Font("Serif", Font.BOLD, 18));  // in a bold font


The Checkbox and CheckboxGroup Classes

A Checkbox is a component that has two states: checked and unchecked. The user can change the state of a check box by clicking on it. The state of a checkbox is represented by a boolean value that is true if the box is checked and false if the box is unchecked. A checkbox has a label, which is specified when the box is constructed:

Checkbox showTime = new Checkbox("Show Current Time");

Usually, it's the user who sets the state of a Checkbox, but you can also set the state in your program. The current state of a checkbox is set using its setState(boolean) method. For example, if you want the checkbox showTime to be checked, you would say "showTime.setState(true);". To uncheck the box, say "showTime.setState(false);". You can determine the current state of a checkbox by calling its getState() method, which returns a boolean value.

In many cases, you don't need to worry about events from checkboxes. Your program can just check the state whenever it needs to know it by calling the getState() method. However, a checkbox does generate an event when its state changes, and you can detect this event and respond to it if you want something to happen at the moment the state changes. When the state of a checkbox is changed, it generates an event of type ItemEvent. The associated listener interface is ItemListener. To receive notification of item events from a checkbox, an object must implement the ItemListener interface and it must be registered with the checkbox by calling its addItemListener() method. The ItemListener interface defines one method, "public void itemStateChanged(ItemEvent evt)".

For handling ItemEvents, I recommend calling evt.getSource() in the itemStateChanged() method to find out which object generated the event. (Of course, if you are only listening for events from one component, you don't even have to do this.) The getSource() method can be used with any event type, not just ItemEvents. The method evt.getSource() returns the object that generated the event. The returned value is of type Object, but you can type-cast it to another type if you want. Once you know the object that generated the event, you can ask the object to tell you its current state. For example, if you know that the event had to come from one of two checkboxes, cb1 or cb2, then your itemStateChanged() method might look like this:

          public void itemStateChanged(ItemEvent evt) {
             Object source = evt.getSource();
             if (source == cb1) {
                boolean newState = cb1.getState();
                ... // respond to the change of state
             }
             else if (source == cb2) {
                boolean newState = cb2.getState();
                ... // respond to the change of state
             }
          }

Closely related to checkboxes are radio buttons. Radio buttons occur in groups. At most one radio button in a group can be checked at any given time. In Java, a radio button is just an object of type Checkbox that is a member of such a group. An entire group of radio buttons is represented by an object belonging to the class CheckboxGroup. The class CheckBoxGroup has methods

            public void setSelectedCheckbox(Checkbox box);
            public Checkbox getSelectedCheckbox();

for selecting one of the checkboxes in the group, and for discovering which box is currently selected. The getSelectedCheckbox() method will return null if none of the boxes in the group is currently selected.

To create a group of radio buttons, you should first create an object of type CheckboxGroup. To create the individual buttons, use the constructor

        Checkbox(String label, CheckboxGroup group, boolean state);

The third parameter of this constructor specifies the initial state of the checkbox. Remember that at most one of the checkboxes in the group can have its state set to true. For example:

          CheckboxGroup colorGroup = new CheckboxGroup();
          Checkbox red   = new Checkbox("Red", colorGroup, false);
          Checkbox blue  = new Checkbox("Blue", colorGroup, false);
          Checkbox green = new Checkbox("Green", colorGroup, true);
          Checkbox black = new Checkbox("Black", colorGroup, false);

This creates a group of four radio buttons labeled "Red", "Blue", "Green", and "Black". Initially, the third button is selected. You still have to add the Checkboxes, individually, to some container. The CheckboxGroup itself is not a component and cannot be added to a container. To actually use the buttons effectively in your program, you would presumably want to store either the CheckboxGroup object or the individual Checkbox objects in instance variables. ItemEvents are generated by each individual Checkbox object when its state changes. Again, you can often ignore these events and simply ask the CheckboxGroup which Checkbox is selected, whenever you have a need to know. If you do want to respond to ItemEvents, you need to register your listener with each of the Checkboxes individually.


The Choice Class

A CheckBoxGroup is one way of allowing the user to select one option from a predetermined set of options. The Choice class represents another way of doing the same thing. An object of type Choice, however, presents the options in the form of a menu. The menu lists a number of items. Only the selected item is displayed. However, when the user clicks on the Choice component, the entire list is displayed, and the user can select one of the items from the list. (There are three types of menus in Java: Choice menus, pop-up menus, and pull-down menus. Pop-up menus and pull-down menus are not Components. I'll discuss pop-up menus later in this section and pull-down menus in Section 7. In fact, Choice components are not technically considered to be menus, but it's hard to find another word that adequately describes what they do.)

When a Choice object is first constructed, it initially containes no items. An item is added to the bottom of the menu by calling its instance method, add(String). The getItemCount() method returns an int that gives the number of items in the list, and the method

public String getItem(int index)

gets the item in position number index in the list. (Items are numbered starting with zero, not one.) Other useful methods are:

          public int getSelectedIndex();
          public String getSelectedItem();
          public void select(int index);
          public void select(String itemName);

These methods serve the obvious purposes (noting that an item can be referred to either by its position in the list or by the actual text of the item).

For example, the following code will create an object of type Choice that contains the options Red, Blue, Green, and Black:

          Choice colorChoice = new Choice();
          colorChoice.add("Red");
          colorChoice.add("Blue");
          colorChoice.add("Green");
          colorChoice.add("Black");

The most common way to use a Choice menu is to call its getSelectedIndex() method when you have a need to know which item in the menu is currently selected. However, like Checkboxes, Choice components generate ItemEvents. You can register an itemListener with the Choice component if you want to respond to such events when they occur.


The List Class

An object of type List is very similar to a Choice object. However, a List is presented on the screen as a scrolling list of items. Furthermore, you can create a List in which it is possible for the user to select more than one item in the list at the same time. The constructor for a List object takes the form

        List(int itemsVisible, boolean multipleSelectionsAllowed);

The fist parameter tells how many items are visible in the list at one time; if the list contains more than this number of items, then the user can use a scroll bar to scroll through the list. The second parameter determines whether or not the user can select more than one item in the list at the same time. If you leave out the second parameter, multiple selections are not allowed.

The List class includes the add(String) method to add an item to the end of the list. You can also add an item in a specified position in the list using the add(String,int) method. (Items are numbered starting from zero.) The getItemCount() method returns an int giving the number of items in the list. The method remove(int) deletes the item at a specified position, while remove(String) removes a specified item. The select(int) method can be used to select the item at the specified position in the list, and deselect(int) unselects the item.

If exactly one item in the list is selected, then the method getSelectedIndex() will return the index of that item, and getSelectedItem() will return the item itself. However, if no items are selected or if more than one item is selected, then getSelectedIndex() will return -1, and getSelectedItem() will return null. In that case, you can use the methods getSelectedItems() and getSelectedIndexes() to determine which items are selected. (However, these two methods return "arrays", which I will not cover until Chapter 8.)

A List generates events of type ItemEvent, and you can register an ItemListener with a List if you want. An ItemEvent is generated whenever an item is selected. In the case of a list that allows multiple selections, an ItemEvent is also generated whenever an item is deselected. A List also generates an event of type ActionEvent when the user double-clicks on an item. The action command associated with such an ActionEvent is the text of the item on which the user double-clicked.


The TextField and TextArea Classes

TextFields and TextAreas are boxes where the user can type in and edit text. The difference between them is that a TextField contains a single line of editable text, while a TextArea displays multiple lines and might include scroll bars that the user can use to scroll through the entire contents of the TextArea. (It is also possible to set a TextField or TextArea to be read-only so that the user can read the text that it contains but cannot edit the text.)

Both TextField and TextArea are subclasses of TextComponent, which is itself a subclass of Component. The TextComponent class supports the idea of a selection. A selection is a subset of the characters in the TextComponent, including all the characters from some starting position to some ending position. The selection is hilited on the screen. The user selects text by dragging the mouse over it. Some useful methods in class TextComponent include the following. They can, of course, be used for both TextFields and TextAreas.

       public void setText(String newText);  // substitute newText 
                                             //   for current contents
       public String getText();  // return a copy of the current contents
       public String getSelectedText();  // return the selected text
       public select(int start, int end);  // change the selected range;
           // characters in the range  start <= pos < end  are
           // selected; characters are numbered starting from zero
       public int getSelectionStart();  // get starting point of selection
       public int getSelectionEnd();  // get end point of selection
       public void setEditable(boolean canBeEdited);
          // specify whether or not the text in the component
          // can be edited by the user

The constructor for a TextField takes the form

         TextField(int columns);

where columns specifies the number of characters that should be visible in the text field. This is used to determine the width of the text field. (Because characters can be of different sizes, the number of characters visible in the text field might not be exactly equal to columns.) You don't have to specify the number of columns; for example, you might want the text field to expand to the maximum size available. In that case, you can use the constructor TextField(), with no parameters. You can also use the following constructors, which specify the initial contents of the text field:

         TextField(String contents);
         TextField(String contents, int columns);

The constructors for a TextArea are

         TextArea();
         TextArea(int lines, int columns);
         TextArea(String contents);
         TextArea(String contents, int lines, int columns);

The parameter lines specifies how many lines of text are visible in the text area. This determines the height of the text area. (The text area can actually contain any number of lines; a scroll bar is used to reveal lines that are not currently visible.) It is common to use a TextArea as the Center component of a BorderLayout. In that case, it isn't useful to specify the number of lines and columns, since the TextArea will expand to fill all the space available in the center area of the container.

The TextArea class adds a few useful procedures to those inherited from TextComponent:

         public void append(String text);
               // add the specified text at the end of the current
               // contents; line breaks can be inserted by using the 
               // special character \n
         public void insert(String text, int pos);
               // insert the text, starting at specified position
         public void replaceRange(String text, int start, int end);
               // delete the text from position start to position end
               //    and then insert the specified text in its place

A TextField generates an ActionEvent when the user presses return while typing in the TextField. The TextField class includes an addActionListener() method that can be used to register a listener with a TextField. In the actionPerformed() method, the evt.getActionCommand() method will return a copy of the text from the TextField. TextAreas do not generate action events.


The ScrollBar Class

Finally, we come to the ScrollBar class. A ScrollBar allows the user to select an integer value from a range of values. A scroll bar can be either horizontal or vertical. It has five parts:

(picture of a scroll bar)

The position of the tab specifies the currently selected value. The user can move the tab by dragging it or by clicking on any of the other parts of the scroll bar. On some platforms, the size of the tab tells what portion of a scrolling region is currently visible. It is actually the position of the bottom or left edge of the tab that represents the currently selected value.

A scroll bar has four associated integer values:

These values can be specified when the scroll bar is created. The constructor takes the form

      Scrollbar(int orientation, int value, int visible, int min, int max);

The orientation, which specifies whether the scroll bar is horizontal or vertical, must be one of the constants Scrollbar.HORIZONTAL or Scrollbar.VERTICAL. The value must be between min and (max - visible). You can leave out all the int parameters to get a scroll bar with default values. You can set the value of the scroll bar at any time with the method setValue(int). If you want to set any of the other parameters, you have to set them all, using

       public void setValues(int value, int visible, int min, int max);

Methods getValue(), getVisibleAmount(), getMinimum() and getMaximum() are provided for reading the current values of each of these parameters.

The remaining question is, how far does the tab move when the user clicks on the up-arrow or down-arrow or in the page-up or page-down region of a scrollbar? The amount by which the value changes when the user clicks on the up-arrow or down-arrow is called the unit increment. The amount by which it changes when the user clicks in the page-up or page-down region is called the block increment. By default, both of these values are 1. They can be set using the methods:

         public void setUnitIncrement(int unitIncrement);
         public void setBlockIncrement(int blockIncrement);

Let's look at an example. Suppose that you want to use a very large canvas, which is too large to fit on the screen. You might decide to display only part of the canvas and to provide scroll bars to allow the user to scroll through the entire canvas. Let's say that the actual canvas is 1000 by 1000 pixels, and that you will show a 200-by-200 region of the canvas at any one time. Let's look at how you would set up the vertical scroll bar. The horizontal bar would be essentially the same.

The visible of the scroll bar would be 200, since that is how many pixels would actually be displayed. The value of the scroll bar would represent the vertical coordinate of the pixel that is at the top of the display. (Whenever the value changes, you have to redraw the display.) The min would be 0, and the max would be 1000. The range of values that can be set on the scroll bar is from 0 to 800. (Remember that the largest possible value is the maximum minus the visible amount.)

The page increment for the scroll bar could be set to some value a little less than 200, say 190 or 175. Then, when the user clicks in the page-up or page-down region, the display will scroll by an amount almost equal to its size. The line increment could be left at 1, but it is likely that this would be too small since it represents a scrolling increment of just one pixel. A line increment of 15 might make more sense, since then the display would scroll by a more reasonable 15 pixels when the user clicks the up-arrow or down-arrow. (Of course, all these values would have to be reset if the display area is resized. Most likely, that would be done by listening for ComponentEvents and defining a componentResized() method to adjust the values of the scroll bars.)

A scroll bar generates an event of type AdjustmentEvent whenever the user changes the value of the scroll bar. The associated AdjustmentListener interface defines one method, "adjustmentValueChanged(AdjustmentEvent evt)", which is called by the scroll bar to notify the listener that the value on the scroll bar has been changed. This method should repaint the display or make whatever other change is appropriate for the new value. The method evt.getValue() returns the current value on the scroll bar. If you are using more than one scroll bar and need to determine which scroll bar generated the event, use evt.getSource() to determine the source of the event.


Pop-up Menus

Pop-up menus differ from all the components discussed above because they are not components and they are not usually visible. The user calls up a pop-up menu by performing some platform-dependent action with the mouse. For example, this might mean clicking with the right mouse button or middle mouse button, or clicking the mouse while holding down the control key. On my Windows computer with a two-button mouse, I have to press both mouse buttons at the same time to call up a pop-up menu.

Here is an applet that uses a pop-up menu. It's an improved version of an applet you saw in Section 5.4. You can place shapes on the drawing area by clicking on the buttons. Once a shape is on the drawing area, you can drag it around. A pop-up menu will appear if you click your mouse on a shape, using the appropriate action for calling up a pop-up menu on your platform. The menu includes commands for changing the color and size of the shape, for deleting the shape, and for moving it to the front of all the other shapes. If you select one of the commands, the menu disappears and the command is carried out. Try it:

Sorry, but your browser
doesn't support Java.

It's not much more difficult to use pop-up menus in a program than it is to use the above components. A pop-up menu generates an ActionEvent when the user selects a command from the menu. The action command associated with that event is the label of the menu item that was selected. You can register an ActionListener with the menu to listen for commands from the menu.

A pop-up menu is an object belonging to the class PopupMenu. A newly created pop-up menu is empty. Items can be added to the menu with its add(String) method. A separator line can be added with the addSeparator() method. (There's a lot more you can do with menu items, if you want to look it up.) If pmenu is a pop-up menu, it can be added to a component, comp, by calling comp.add(pmenu). However, this does not make the menu appear on the screen. To make a menu appear, a program has to call pmenu.show(comp,x,y). The pop-up menu appears with its upper-left corner at the point (x,y), where the coordinates are given in comp's coordinate system.

The only other question is when to show the menu. It should be shown when the user performs the platform-dependent mouse action that is used for calling up pop-up menus -- assuming that the action is performed in a context where popping up the menu makes sense. (In the above applet, for example, that means only when the user is clicking on a shape). To hear such actions, you have to listen for mouse events from the component. A MouseEvent, evt, has a boolean-valued method, evt.isPopupTrigger() that you can call to determine whether the user is trying to pop up a menu. This could theoretically occur in either the mousePressed or in the mouseReleased method, so you should test for the pop-up trigger in both of these methods. The mousePressed method might look something like this (mouseReleased would be similar):

         public void mousePressed(MouseEvent evt) {
            if (evt.isPopupTrigger()) {
               int x = evt.getX();
               int y = evt.getY();
               ... // Maybe test if it makes sense to show the menu here.
               pmenu.show(this,x,y);  // Assume that "this" is a component
                                      //   that is listening for its own
                                      //   mouse events and that pmenu is
                                      //   the pop-up menu that has been 
                                      //   added to that component.
            }
            else {
               ...// handle a normal mouse click
            }
         }

Note that this method just makes the menu appear on the screen. Any command generated by that menu must be handled elsewhere, in an actionPerformed method. The source code for the above applet can be found in the file ShapeDrawWithMenu.java. Look there for a realistic example of using pop-up menus.


[ Next Section | Previous Section | Chapter Index | Main Index ]