Buttons

The simplest input controls of all are buttons. There are three types of buttons: the simple button, the radio button, and the check box. The following ButtonDemo apps demonstrate all three button types.

Reading Button Values

The ButtonDemo1 program, whose code is shown later in this chapter, outputs a single test string in one of three different fonts. In addition, the test string can be formatted as boldface or italic. These settings are controlled using buttons of different types.

Since the choice of font is mutually exclusive, I chose to set the font using a set of three radio buttons. The boldface and italic properties are independent, so I chose to use a separate check box for each of these options. A Submit button at the bottom causes the button settings to take effect. An edit box across the top of the window displays a test string in the selected font type and format.

NOTE
Use check boxes to set properties that are both binary ("on" or "off") and independent of each other. Use radio buttons to set properties that are mutually exclusive. Use a regular push button to take some action.

Forms Designer work

To begin, create the button demonstration app using the Windows app builder. (Choose New Project from the File menu. The default project type is Windows app.) Give this first version of the program the name ButtonDemo1. Open the Project Explorer window and double-click on Form1.java to bring up the Forms Designer. From this point, start dragging objects from the Toolbox to the Forms Designer. Figure 6-1 shows the Forms Designer and the Properties window for one of the buttons during the later stages of developing the ButtonDemo1 app.

The check boxes are straightforward to create. Select the CheckBox tool in the Toolbox, and place it in the Forms Designer. Once you've placed the check box, just start typing the label; the Forms Designer will automatically update the check box's text property in the Properties window. I also chose to change the name by editing the name property in the Properties window. It's a good idea to use names that are a combination of the button label and the button type. Thus, checkBox1 becomes boldCheckBox and checkBox2 becomes italicsCheckBox.

For the radio buttons, you will first need to build a group box. A group box groups radio buttons both visually and logically. The group box groups radio buttons visually by placing a small box around them. It groups the radio buttons logically in that the radio buttons contained within a group box are mutually exclusive: choosing one radio button causes all other radio buttons in the same group box to not be chosen.

Select the GroupBox control in the Toolbox and drag it to the Forms Designer. Now resize the group box to be large enough to hold three radio buttons and their labels.

Java Click to view at full size.

Screenshot-1. The ButtonDemo1 app in the Forms Designer during the final stages of construction.

NOTE
When initially placing objects in the Forms Designer, don't worry too much about their exact dimensions. You can always resize things once you get all the objects in place on the form. In addition, there are two ways to place any control in a form: you can either drag the control from the Toolbox and drop it on the form, or you can click the control and then click within the form. There is no difference.

Once the group box is in place, you can begin adding radio button controls. For this app, you will need three radio buttons, each titled with the name of a font. Making sure that the radio boxes are properly aligned is easy when you have the Snap To Grid feature of the Forms Designer enabled. You will also need to set one of the radio buttons to be initially chosen—by default, radio buttons are not chosen.

NOTE
Users are accustomed to seeing one (and only one) radio button in a set selected at all times. Starting the app with none selected is confusing.

I selected the first radio button, the Courier button, to be initially chosen by setting the checked property to true in the Properties window, as shown in Figure 6-1.

An Edit control across the top and a Submit button near the bottom finishes the design of the ButtonDemo1 app's form.

code

After adding functionality, the code for the ButtonDemo1 app is as follows:

import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import com.ms.wfc.html.*;
/**
 * This class demonstrates the different button types.
 */
public class Form1 extends Form
{
 public Form1()
 {
 // Required for Visual J Plus Plus Form Designer support
 initForm();
 // at startup act like the Submit button has been
 // pushed; this will create the initial font and
 // update the outputEdit field with the test message
 submitButton_click(null, null);
 }
 /**
 * Form1 overrides dispose so it can clean up the
 * component list.
 */
 public void dispose()
 {
 super.dispose();
 components.dispose();
 }
 /**
 * Handle the Submit button by reading the button settings,
 * creating a font to match, and then updating the
 * text in the outputEdit object with that font.
 */
 private void submitButton_click(Object source, Event e)
 {
 // create a font based on the button settings
 // first; read the check boxes
 boolean bold = boldCheckBox.getChecked();
 boolean italics = italicsCheckBox.getChecked();
 // convert the weight check box into an integer
 // by choosing the appropriate weight from the list
 // of possibilities
 int weight = bold ? FontWeight.BOLD : FontWeight.NORMAL;
 // now find which radio button is selected; get a
 // list of all the radio buttons attached to the
 // Font group box, and loop through to see which one is
 // checked
 String fontName = null;
 Control[] control = fontGroupBox.getControls();
 for (int i = 0; i < control.length; i++)
 {
 // if this radio button is checked…
 RadioButton rb = (RadioButton)control[i];
 if (rb.getChecked())
 {
 // then use the name on the button as
 // the font name
 fontName = rb.getText();
 }
 }
 // create a font with the data
 Font font = new Font(fontName, 14, FontSize.POINTS,
 weight, italics, false, false);
 // now update the outputEdit field with the font
 outputEdit.setText("This is a test string.");
 outputEdit.setFont(font); }
 /**
 * NOTE: The following code is required by the Visual J Plus Plus form
 * designer. It can be modified using the form editor. Do not
 * modify it using the code editor.
 */
 Container components = new Container();
 Edit outputEdit = new Edit();
 CheckBox boldCheckBox = new CheckBox();
 CheckBox italicsCheckBox = new CheckBox();
 GroupBox fontGroupBox = new GroupBox();
 RadioButton courierRadioButton = new RadioButton();
 RadioButton arialRadioButton = new RadioButton();
 RadioButton haettenschweillerRadioButton = new RadioButton();
 Button submitButton = new Button();
 private void initForm()
 {
 this.setText("Button Demo");
 this.setAutoScaleBaseSize(new Point(5, 13));
 this.setClientSize(new Point(245, 184));
 outputEdit.setLocation(new Point(20, 10));
 outputEdit.setSize(new Point(200, 20));
 outputEdit.setTabIndex(0);
 outputEdit.setText("");
 outputEdit.setReadOnly(true);
 boldCheckBox.setLocation(new Point(20, 50));
 boldCheckBox.setSize(new Point(50, 25));
 boldCheckBox.setTabIndex(1);
 boldCheckBox.setText("Bold");
 italicsCheckBox.setLocation(new Point(20, 80));
 italicsCheckBox.setSize(new Point(50, 25));
 italicsCheckBox.setTabIndex(2);
 italicsCheckBox.setText("Italics");
 fontGroupBox.setLocation(new Point(90, 40));
 fontGroupBox.setSize(new Point(130, 90));
 fontGroupBox.setTabIndex(3);
 fontGroupBox.setTabStop(false);
 fontGroupBox.setText("Font");
 courierRadioButton.setLocation(new Point(10, 20));
 courierRadioButton.setSize(new Point(100, 25));
 courierRadioButton.setTabIndex(0);
 courierRadioButton.setTabStop(true);
 courierRadioButton.setText("Courier");
 courierRadioButton.setChecked(true);
 arialRadioButton.setLocation(new Point(10, 40));
 arialRadioButton.setSize(new Point(100, 25));
 arialRadioButton.setTabIndex(1);
 arialRadioButton.setText("Arial");
 haettenschweillerRadioButton.setLocation(new Point(10, 60));
 haettenschweillerRadioButton.setSize(new Point(110, 25));
 haettenschweillerRadioButton.setTabIndex(2);
 haettenschweillerRadioButton.setText("Haettenschweiller");
 submitButton.setLocation(new Point(80, 150));
 submitButton.setSize(new Point(75, 23));
 submitButton.setTabIndex(4);
 submitButton.setText("Submit");
 submitButton.addOnClick(
 new EventHandler(this.submitButton_click));
 this.setNewControls(new Control[] {
 submitButton, fontGroupBox, italicsCheckBox, boldCheckBox, outputEdit});
 fontGroupBox.setNewControls(new Control[] {
 haettenschweillerRadioButton,
 arialRadioButton, courierRadioButton});
 }
 /**
 * The main entry point for the app. *
 * @param args Array of parameters passed to the app
 * via the command line.
 */
 public static void main(String args[])
 {
 app.run(new Form1());
 }
}


As always, the initForm() method is created automatically by the Forms Designer. In one way, this initForm() method is different from the versions we have seen so far: it contains a hierarchy of objects. Instead of adding the radio buttons to the form, this initForm() adds them to the fontGroupBox object. The fontGroupBox object is then added to the form.

Grouping the radio buttons in the fontGroupBox container is what makes the radio buttons mutually exclusive. This also enables us to read the radio button values out of the container, as you will see later.

Double-clicking the Submit button in the Forms Designer created and registered the submitButton_click() method, and then I manually added the functionality for the button to the method. This method first reads the two check boxes boldCheckBox and italicsCheckBox. The Boolean bold value is then turned into an integer font weight value by using the enumerated class FontWeight.

To determine which font radio button is selected, submitButton_click() loops through the radio buttons contained in the fontGroupBox container. It does this by first calling the fontGroupBox.getControls() function. This function returns an array containing references to the objects contained within the fontGroupBox object. Since we didn't add anything but radio buttons to the group box, all of these Control objects are of type RadioButton. As soon as the loop finds a button whose getChecked() method returns true, the function reads the name of the button by calling getText(). The name of the button is the name of the font we want to be applied.

Armed with this information, submitButton_click() creates a Font object. It then applies the font and font format to the text in the outputEdit Edit control. An example of output from this program is shown in Figure 6-2.

Screenshot

Screenshot-2. Output from ButtonDemo1 showing a particularly attractive font selection.

Handling Button Updates Automatically

In many apps, you would like the button settings to take effect immediately rather than after the user clicks on a submit button of some type. The ButtonDemo2 app beginning below updates the ButtonDemo1 functionality so that clicking any of the check boxes or radio buttons causes the displayed text to be updated immediately. Accordingly, the Submit button has been removed. Note that the initForm() function isn't included in the following code but is present in the code contained on the companion CD.

import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import com.ms.wfc.html.*;
/**
 * This class demonstrates the different button types.
 */
public class Form1 extends Form
{
 // maintain the state of the object
 boolean italics;
 boolean bold;
 String fontName = "Courier";
 public Form1()
 {
 // Required for Visual J Plus Plus Form Designer support
 initForm();
 // update the output to display the initial state
 updateState();
 }
 /**
 * Form1 overrides dispose so it can clean up the
 * component list.
 */
 public void dispose()
 {
 super.dispose();
 components.dispose();
 }
 /**
 * Update the output edit field to reflect the current
 * state.
 */
 private void updateState()
 {
 // convert the weight into an integer
 // by choosing the appropriate weight
 // from the list of possibilities
 int weight = bold ? FontWeight.BOLD : FontWeight.NORMAL;
 // create a font from the current state
 Font font = new Font(fontName, 14, FontSize.POINTS,
 weight, italics, false, false);
 // now update the outputEdit field with the font
 outputEdit.setText("This is a test string.");
 outputEdit.setFont(font); }
 private void boldCheckBox_click(Object source, Event e)
 {
 CheckBox cb = (CheckBox)source;
 bold = cb.getChecked();
 updateState();
 }
 private void italicsCheckBox_click(Object source, Event e)
 {
 CheckBox cb = (CheckBox)source;
 italics = cb.getChecked();
 updateState();
 }
 private void radioButton_checkedChanged(Object source, Event e)
 {
 RadioButton rb = (RadioButton)source;
 if (rb.getChecked())
 {
 fontName = rb.getText();
 }
 updateState();
 }
 /**
 * NOTE: The following code is required by the Visual J Plus Plus form
 * designer. It can be modified using the form editor. Do not
 * modify it using the code editor.
 */
 Container components = new Container();
 Edit outputEdit = new Edit();
 CheckBox boldCheckBox = new CheckBox();
 CheckBox italicsCheckBox = new CheckBox();
 GroupBox fontGroupBox = new GroupBox();
 RadioButton courierRadioButton = new RadioButton();
 RadioButton arialRadioButton = new RadioButton();
 RadioButton haettenschweillerRadioButton = new RadioButton();
 private void initForm()
 {
 // …created by Forms Designer…
 }
 /**
 * The main entry point for the app. * …
 */
 public static void main(String args[])
 {
 app.run(new Form1());
 }
}


This version contains several data members that represent the state of the object. The variable italics is true when the font is to be italicized. Similarly, the variables bold and fontName represent further font state information.

The event handler that previously handled the Submit button is now somewhat simplified because it no longer reads the button settings directly. In addition, I renamed the handler to updateState(). The updateState() method updates the output edit text to reflect the current state of the form object as stored in its data members.

The event handlers such as boldCheckBox_click() and italicsCheckBox_click() are called when the user selects or clears the check box. These methods update the state of the object by updating the appropriate data member and then invoking updateState() to reflect the new state information in the output text.

Using the active properties page of the Properties window

The same approach of using one method per button could have been applied to the radio buttons as well; however, a large number of radio buttons can result in a lot of very small event handler functions. As a demonstration of another approach, I included in ButtonDemo2 the function radioButton_checkedChanged() to handle a change in state of any of the radio buttons. To use a common function to handle multiple buttons, you can't use the simpler double-click method to establish the event handler. Double-clicking a button causes the Forms Designer to create a unique handler for that button.

To establish an existing function as an event handler or to establish an event handler for an object other than the object's default event, you must use the active properties page of the Properties window. Open the Properties window, and click the object to make the properties of the object visible. Now click the Events button (with the lightning bolt symbol) at the top of the Properties window. This switches the Properties window display to show the events this object receives. These are the active properties of the object, as opposed to the passive data properties of the object we have been viewing up until now.

For the previous example, I chose to attach my radioButton_checkedChanged() method to the checkedChanged event of each of the radio buttons. This event occurs whenever the selection state of the button changes—that is to say, when a button goes from checked to unchecked or the other way around. To attach the method to the event, click the checkedChanged event property and click on the arrow in the property setting box. This displays all of the methods in Form1.java that have the proper prototype to handle the checkedChanged event—that is, all methods that return a void and take an Object and an Event as arguments. I selected my radioButton_checkedChanged() method from the drop-down list, as shown in Figure 6-3. This list also includes the event handlers for the bold and italics buttons, since their prototypes also match the requirements for the checkedChanged event. If you have yet to write the method you want to attach to the button, you can alternatively type what will be the function name into the property setting box.

Screenshot

Screenshot-3. The Properties window showing the active properties of the object—the events that object receives.

The radioButton_checkedChanged() method is only slightly more complicated than its check box equivalents. The checkedChanged event occurs when the radio button is being checked either on or off. This would be important if we were saving the state of the radio buttons as a set of Boolean variables. However, since we are only saving the name of the currently checked radio button we want to ignore the event triggered on the radio button as it goes from on to off; hence the rb.getChecked() test at the beginning of the radioButton_checkedChanged() method.

The output from ButtonDemo2 appears identical to its predecessor except for the absence of the Submit button.

state approach to handling events

The state event-handling approach used by ButtonDemo2 is common: record the states of the buttons and menu selections within data members of the object and then use a single updateState() method to output that state information. This approach has the following advantages:

Comments