# 3

# JCCheckbox and JCCheckboxGroup

Introduction · Sample Program Code · Button Styles

Setting Button Colors · Events · Property Listing

Example Program

## Introduction

A checkbox is a labeled toggle button. A group of these toggle buttons that function together form a checkbox group. A checkbox can send an action event after it is pushed, just like any other button, or a program can check on the state of the buttons when the user commits a separate action, such as pressing a "Submit" button. Checkboxes provide the user with a range of options that can either be additive (checkboxes) or mutually exclusive (radio buttons). Checkboxes are used to present multiple options to a user, while radio buttons only permit the use a single choice from a list of choices.

In the Abstract Window Toolkit (AWT), individual checkbox components are laid out within a panel, and their behavior controlled by the AWT `CheckboxGroup` . `CheckboxGroup` is neither a component nor a container; it is essentially a helper object that tracks and coordinates the function of individual Checkbox objects. The `CheckboxGroup` class does not allow direct access to the checkboxes it manages. This makes the task of manipulating checkbox groups awkward. When using AWT checkbox components, it is not possible to produce any form of checkbox type other than those displaying radio button behavior, which severely restricts its usefulness.

`JCCheckbox` and `JCCheckboxGroup` provides the programmer with the tools necessary to create a wide variety of checkbox styles, and the means to easily control and read their values. Individual `JCCheckbox` components present a checkbox with an accompanying label whose values are controlled by `JCCheckboxGroup`. The `JCCheckbox` group is a container that can set the state of the checkboxes it contains, and can easily pass that state on to the rest of the program. If a group's `RadioBehavior` is set to `true`, buttons added to the group will appear as radio buttons.

Individual checkboxes and radio buttons can appear disabled and their appearance "grayed-out" through the use of callbacks. They can also represent multiple states in addition to "on" an "off"; this " mixed-value" state represents an option that is currently unavailable but becomes active under different circumstances. The mixed-value state is displayed as a stippled checkbox or radio button.

#### Behavior

`JCCheckbox` behaves in the following manner:

- when the checkbox is pressed, it is displayed in its next state
- if the checkbox is pressed and the mouse is dragged outside of the button area, the checkbox is displayed in its original state, i.e. the activation is temporarily cancelled until the mouse is dragged within the checkbox
- if the mouse button is pressed and then released within the checkbox, the checkbox is displayed to its next state
- while the checkbox has focus, a black border encloses the individual checkbox until it loses focus
- if the space key is depressed, the checkbox is displayed in its next state. This is equivalent to clicking it with the mouse.

`JCCheckboxGroup` is displayed in the following manner:

- a border is drawn around the checkboxes, and a title label (if set) is displayed at the top of the border
- pressing the up and down cursor keys moves focus between individual checkboxes, and the tab key traverses between checkbox groups by highlighting the first checkbox within the checkbox group.

#### Keyboard Traversal

When a `JCCheckbox` has focus, hitting the SPACE BAR key will select a previously unselected checkbox, or unselect a previously selected checkbox. Radio buttons work in a similar manner, but will not unselect a previously selected radio button. The UP and DOWN cursor keys move the focus of a radio button/checkbox in the direction of the cursor key.

## Sample Program Code

`JCCheckboxGroup` is subclassed from `JCGroupBox`, therefore any component can be added to it. To specify that a `radioButton` checkbox which is not a direct child of a `checkBox` group be controlled by it, call the button's `setGroup()` method.

The following code displays two separate checkbox groups consisting of a series of radio buttons and checkboxes respectively. This program illustrates the most common use of `JCCheckbox`: listing a variety of choices, one or more of which can be selected.

    package jclass.bwt.examples;
    import jclass.bwt.BWTEnum;
    import jclass.bwt.JCButtonEvent;
    import jclass.bwt.JCButtonListener;
    import jclass.bwt.JCCheckbox;
    import jclass.bwt.JCCheckboxGroup;
    import jclass.contrib.ContribFrame;
    import jclass.util.JCString;
    import jclass.util.JCUtilConverter;
    import java.awt.*;
    import java.applet.*;
    import jclass.bwt.JCItemEvent;
    import jclass.bwt.JCItemListener;
    /**
     * This example demonstrates various types of JCCheckboxes and their
     * use within a JCCheckboxGroup.
     */
    public class checkboxes extends Applet implements JCItemListener {
    static String radio_labels[] = {
    	"Read-only", "Read and write", "Depends on password"
    };
    static String checkbox_labels[] = {
    	"Invert text files", "Create GIF files", "Auto Center", "Prompt for Destination"
    };
    static String rotation_files[] = {
    	"../images/rotate000.gif",
    	"../images/rotate270.gif",
    	"../images/rotate180.gif",
    	"../images/rotate090.gif",
    };
    static Image rotation_images[] = new Image[4];
    static String rotation_labels[] = {
    	"North", "East", "South", "West"
    };
    static String style_labels[] = {
    	"Fill",
    	"Check",
    	"Circle",
    	"Cross",
    	"Diamond",
    };
    static int style_indicators[] = {
    	BWTEnum.INDICATOR_FILL,
    	BWTEnum.INDICATOR_CHECK,
    	BWTEnum.INDICATOR_CIRCLE,
    	BWTEnum.INDICATOR_CROSS,
    	BWTEnum.INDICATOR_DIAMOND,
    };
    static Image secure_images[] = new Image[2];
    static String secure_image_files[] = {
    	"../images/check16.gif",
    	"../images/x16.gif",
    };
    JCCheckbox image_button;
    /* ItemListener method
     * Changes button's image to match state
     */
    public void itemStateChanged(JCItemEvent ev) {
    	if (ev.getSource() == image_button)
    		image_button.setLabel(rotation_labels[image_button.getState()]);
    }
    public void init() {
    	setBackground(Color.lightGray);
    	JCCheckboxGroup radios = JCCheckbox.makeGroup(radio_labels, null, true);
    	radios.setTitle("Radio Buttons");
    	add(radios);
    	JCCheckboxGroup checks = JCCheckbox.makeGroup(checkbox_labels, null, false);
    	checks.setTitle("Check Boxes");
    	add(checks);
    	JCCheckbox box1 = checks.getCheckbox(2);
    	box1.setState(1);
    	JCCheckbox box2 = checks.getCheckbox(3);
    	box2.setState(1);

    	/*
    	 * Image selector
    	 */
    	JCCheckboxGroup imagebox = new JCCheckboxGroup("Images");
    	imagebox.setRadioBehavior(false);
    	JCCheckbox secure_button = new JCCheckbox("Secure", 0, imagebox);
    	for (int i=0; i < secure_images.length; i++)
    		secure_images[i] = CUtilConverter.toImage(this, secure_image_files[i]);
    	secure_button.setIndicator(BWTEnum.INDICATOR_IMAGE);
    	secure_button.setIndicatorImageList(secure_images);
    	secure_button.setNumStates(secure_images.length);
    	image_button = new JCCheckbox();
    	for (int i=0; i < rotation_images.length; i++)
    		rotation_images[i] = JCUtilConverter.toImage(this, rotation_files[i]);
    	image_button.setIndicator(BWTEnum.INDICATOR_IMAGE);
    	image_button.setIndicatorImageList(rotation_images);
    	image_button.setLabel(rotation_labels[0]);
    	image_button.setNumStates(rotation_images.length);
    	image_button.addItemListener(this);
    	imagebox.add(image_button);
    	add(imagebox);
    	JCCheckboxGroup styles = new JCCheckboxGroup("Styles");
    	styles.setRadioBehavior(false);
    	for (int i=0; i < style_labels.length; i++) {
    		JCCheckbox btn = new JCCheckbox();
    		btn.setState(BWTEnum.ON);
    		if (style_indicators[i] == BWTEnum.INDICATOR_FILL) {
    			btn.setUnselectColor(Color.red);
    			btn.setSelectColor(Color.green);
    		}
    		btn.setLabel(style_labels[i]);
    		btn.setIndicator(style_indicators[i]);
    		styles.add(btn);
    	}
    	add(styles);
    }

    public static void main(String args[]) {
    	ContribFrame frame = new ContribFrame("Checkboxes");
    	checkboxes s = new checkboxes();
    	s.init();
    	frame.add(s);
    	frame.pack();
    	frame.show();
    }
    }

This code uses `makeGroup` to create an array of labels and an array of values, and creates a group of radio buttons with associated values for each button. `makeCollection` takes the same parameters and produces an array of individual check boxes.

This code produces the checkbox group and the individual checkboxes displayed in the following illustration.

Sample radio buttons and check boxes displayed

This sample code is incorporated into the example file checkboxes.class provided with JClass BWT. For information on how to run this program, see the " Example Program " section at the end of this chapter.

## Button Styles

By default, `JCCheckbox` components are either "on" (selected) or "off" (deselected). The `State` property specifies the current state of the component. If this property is set to `ON`, the component is in the on state; if it is set to `OFF`, the component is in the off state. When the end-user presses the toggle button, this property toggles between `ON` and `OFF`.

If `NumStates` is set to a value more than 2, the button can represent a third "mixed-state" display, and the checkbox or radio button has a stippled display.

#### State Indicators

Each `JCCheckbox` component contains an indicator which specifies the current state of the toggle button. The `Indicator` property controls the style of the indicator, and is set to one of the following:

IndicatorProperty Value | Resulting Indicator Style | Appearance When In Off State | Appearance When In On State
--- | --- | --- | ---
`INDICATOR_FILL` | initial raised foreground color appears depressed when activated |  |
`INDICATOR_CHECK` | black checkmark drawn in a square checkbox with a white background |  |
`INDICATOR_CIRCLE` | black circle drawn in a circular checkbox with a white background |  |
`INDICATOR_CROSS` | black cross drawn in a square checkbox with a white background |  |
`INDICATOR_`DIAMOND | diamond drawn in the foreground color; diamond appears raised when activated |  |
`INDICATOR_IMAGE` | indicator is a image | see below

When the `Indicator` property is set to `INDICATOR_IMAGE`, the list of indicator images to use is specified by the `IndicatorImageList` property.

#### Multiple States

You can specify any number of component states you like. To do this, set the `NumStates` property. When this property is set to a value greater than `2`, the value of `State` begins at `0` and increases by one each time the end-user presses the toggle button. When the largest state value is reached (one less than the number of states), a subsequent button press cycles `State` back to `0` (which is equivalent to `OFF`).

The following code fragments illustrate how a sequence of images can be successively displayed in a checkbox. Multiple component states are often used with application-defined indicator styles. The following code defines a four-state toggle button, specifying an indicator image list and image list for the four states:

    static String rotation_files[] = {
            "../images/rotate000.gif",
            "../images/rotate270.gif",
            "../images/rotate180.gif",
            "../images/rotate090.gif",
    };
    static Image rotation_images[] = new Image[4];
    static String rotation_labels[] = {
            "North", "East", "South", "West"
    ...
    JCCheckboxGroup imagebox = new JCCheckboxGroup("Images");
    image_button = new JCCheckbox();
            for (int i=0; i < rotation_images.length; i++)
                    rotation_images[i] = JCUtilConverter.toImage(this, rotation_files[i]);
            image_button.setIndicator(INDICATOR_IMAGE);
            image_button.setIndicatorImageList(rotation_images);
            image_button.setLabel(rotation_labels[0]);
            image_button.setNumStates(rotation_images.length);
            image_button.addItemListener(this);
            imagebox.add(image_button);

The following illustration depicts the results of this code when inserted into a program:

A multiple state checkbox displaying different images as it is activated by a user

## Setting Button Colors

The `JCCheckbox` component enables you to set the indicator background color for the `FILL` and `DIAMOND` indicators. To set the indicator background when the toggle is set (when `State` is `BWT.Enum.ON`), set the `SelectColor` property. To set the indicator background when the toggle is not set (when `State` is anything other than `BWT.Enum.OFF`), set the `UnselectColor` property.

The following code fragment displays a Fill checkbox that is red when it is inactive, and green when active:

    JCCheckboxGroup styles = new JCCheckboxGroup("Styles");
            styles.setRadioBehavior(false);
            for (int i=0; i < style_labels.length; i++) {
                    JCCheckbox btn = new JCCheckbox();
                    btn.setState(ON);
                    if (style_indicators[i] == INDICATOR_FILL) {
                            btn.setUnselectColor(Color.red);
                            btn.setSelectColor(Color.green);
                    }
                    btn.setLabel(style_labels[i]);
                    btn.setIndicator(style_indicators[i]);
                    styles.add(btn);
            }
            add(styles);
    }

The results can be seen in the following illustration:

Setting Button Colors Using UnselectColor and SelectColor

## Events

A class can be notified when the user clicks a `JCCheckbox` by implementing the `JCItemListener` interface and registering itself with the checkbox via `addItemListener`, as the following code demonstrates:

    public interface JCItemListener {
            public void itemStateChanged(JCItemEvent e);
    }
    public class JCItemEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type: ITEM_STATE_CHANGED.
            public int getId()
            // Returns the item where the event occurred.
            public Object getItem()
            // Returns the state change type which generated the event: SELECTED or DESELECTED
            public int getStateChange()
    }

A class can be notified when the user clicks any `JCCheckboxGroup` in the group by implementing the `JCItemListener` interface and registering itself with the group via `addItemListener`:

    public interface JCItemListener {
            public void itemStateChanged(JCItemEvent e);
    }
    public class JCItemEvent {
            // Returns the component where the event originated.
            public Object getSource()
            // Returns the event type: ITEM_STATE_CHANGED.
            public int getId()
            // Returns the item where the event occurred.
            public Object getItem()
            // Returns the state change type which generated the event: SELECTED or DESELECTED
            public int getStateChange()
    }

## Property Listing

The following summarizes the properties of `JCCheckbox` and `JCCheckboxGroup`. Complete reference documentation is available online in standard javadoc format in jclass.bwt.JCCheckbox.html and jclass.bwt.JCCheckboxGroup.html.

### jclass.bwt.JCCheckbox

Name | Method | Inherited from
--- | --- | ---
`Background` | `setBackground` | `jclass.bwt.JCComponent`
`DoubleBuffer` | `setDoubleBuffer` | `jclass.bwt.JCComponent`
`Font` | `setFont` | `jclass.bwt.JCComponent`
`Foreground` | `setForeground` | `jclass.bwt.JCComponent`
`HighlightColor` | `setHighlightColor` | `jclass.bwt.JCComponent`
`HighlightThickness` | `setHighlightThickness` | `jclass.bwt.JCComponent`
`Indicator` | `setIndicator` | `jclass.bwt.JCCheckbox`
`IndicatorImageList` | `setIndicatorImageList` | `jclass.bwt.JCCheckbox`
`Insets` | `setInsets` | `jclass.bwt.JCCheckbox`
`Label` | `setLabel` | `jclass.bwt.JCComponent`
`NumStates` | `setNumStates` | `jclass.bwt.JCComponent`
`PreferredSize` | `setPreferredSize` | `jclass.bwt.JCComponent`
`SelectColor` | `setSelectColor` | `jclass.bwt.JCCheckbox`
`State` | `setState` | `jclass.bwt.JCCheckbox`
`Traversable` | `setTraversable` | `jclass.bwt.JCComponent`
`UnselectColor` | `setUnselectColor` | `jclass.bwt.JCCheckbox`
`UserData` | `setUserData` | `jclass.bwt.JCComponent`

### jclass.bwt.JCCheckboxGroup

Name | Method | Inherited from
--- | --- | ---
`Background` | `setBackground` | `jclass.bwt.JCContainer`
`Font` | `setFont` | `jclass.bwt.JCContainer`
`Foreground` | `setForeground` | `jclass.bwt.JCContainer`
`Insets` | `setInsets` | `jclass.bwt.JCContainer`
`Orientation` | `setOrientation` | `jclass.bwt.JCCheckboxGroup`
`PreferredSize` | `setPreferredSize` | `jclass.bwt.JCContainer`
`RadioBehavior` | `setRadioBehavior` | `jclass.bwt.JCCheckboxGroup`
`UserData` | `setUserData` | `jclass.bwt.JCContainer`

## Example Program

Demonstration programs and example code containing `JCCheckbox` and `JCCheckboxGroup` come with JClass BWT. The examples can be viewed in applet form by launching index.html within the /jclass/bwt/examples directory. checkboxes.class can be run as a stand-alone Java application from the command prompt by typing:

    	java jclass.bwt.examples.checkboxes