Home > Articles > Programming > Java

This chapter is from the book

High-Level API

Now that you know the basics of the MIDlet's life cycle and general display model, we can start to look deeper into the lcdui package. We will start with another subclass of Screen: Alert. Then we will discuss some simple Items like StringItem and ImageItem. We will explain the use of more advanced Items such as TextField and ChoiceGroup by creating a simple TeleTransfer example application. As we introduce new MIDP high-level UI capabilities like other Screen subclasses, we will extend the TeleTransfer sample step by step.

Alerts

You already know the Form class from the first example. The simplest subclass of Screen is Alert. Alert provides a mechanism to show a dialog for a limited period of time. It consists of a label, text, and an optional Image. Furthermore, it is possible to set a period of time the Alert will be displayed before another Screen is shown. Alternatively, an Alert can be shown until the user confirms it. If the Alert does not fit on the screen and scrolling is necessary to view it entire contents, the time limit is disabled automatically.

The following code snippet creates an Alert with the title "HelloAlert" and displays it until it is confirmed by the user:

Alert alert = new Alert ("HelloAlert");
alert.setTimeout (Alert.FOREVER);
display.setCurrent (alert);

Forms and Items

The most important subclass of Screen is the class Form. A Form can hold any number of Items such as StringItems, TextFields, and ChoiceGroups. Items can be added to the Form using the append() method.

The Item class itself is an abstract base class that cannot be instantiated. It provides a label that is a common property of all subclasses. The label can be set and queried using the setLabel()and getLabel() methods, respectively. The label is optional, and a null value indicates that the item does not have a label. However, several widgets switch to separate screens for user interaction, where the label is used as the title of the screen. In order to allow the user to keep track of the program state, it is recommended that you provide a label at least for interactive items.

Items can neither be placed freely nor can their size be set explicitly. Unfortunately, it is not possible to implement Item subclasses with a custom appearance. The Form handles layout and scrolling automatically. Table 3.1 provides an overview of all Items available in MIDP.

Table 3.1 All Subclasses of Item

Item

Description

ChoiceGroup

Enables the selection of elements in group.

DateField

Used for editing date and time information.

Gauge

Displays a bar graph for integer values.

ImageItem

Used to control the layout of an Image.

StringItem

Used for read-only text elements.

TextField

Holds a single-line input field.


StringItem

StringItems are simple read-only text elements that are initialized with the label and a text String parameter only. The following code snippet shows the creation of a simple version label. After creation, the label is added to the main form in the constructor of the HelloMidp application:

public HelloMidp () {
  mainForm = new Form ("HelloMidp");
  StringItem versionItem = new StringItem ("Version: ", "1.0");
  mainForm.append (versionItem);
}

The label of the StringItem can be accessed using the setLabel() and getLabel() methods inherited from Item. To access the text, you can use the methods setText() and getText().

ImageItem

Similar to the StringItem, the ImageItem is a plain non-interactive Item. In addition to the label, the ImageItem constructor takes an Image object, a layout parameter, and an alternative text string that is displayed when the device is not able to display the image. The image given to the constructor must be non-mutable. All images loaded from the MIDlet suite's JAR file are not mutable. (Details about adding resources to a JAR file are explained in Chapter 2, "The Connected Limited Device Configuration.")

The difference between mutable and non-mutable Images is described in more detail in the section about Images in the "Low Level API" section of this chapter. For now, we will treat the Image class as a "black box" that has a string constructor that denotes the location of the image in the JAR file. Please note that Image construction from a JAR file throws an IOException if the image cannot be loaded for some reason. The layout parameter is one of the integer constants listed in Table 3.2, where the newline constants can be combined with the horizontal alignment constants.

Table 3.2 ImageItem Layout Constants

Constant

Value

LAYOUT_CENTER

The image is centered horizontally.

LAYOUT_DEFAULT

A device-dependent default formatting is applied to the image.

LAYOUT_LEFT

The image is left-aligned.

LAYOUT_NEWLINE_AFTER

A new line will be started after the image is drawn.

LAYOUT_NEWLINE_BEFORE

A new line will be started before the image is drawn.

LAYOUT_RIGHT

The image is aligned to the right.


The following code snippet shows how a center aligned ImageItem is added to the HelloMidp sample MIDlet:

public HelloMidp () {
  display = Display.getDisplay (this);
  mainForm = new Form ("HelloMidp");
   try {
    ImageItem logo = new ImageItem
      ("Copyright: ", Image.createImage ("/mcp.png"),
       ImageItem.LAYOUT_CENTER | ImageItem.LAYOUT_NEWLINE_BEFORE
       | ImageItem.LAYOUT_NEWLINE_AFTER, "Macmillian USA");

     mainForm.append (logo);
  }
  catch (IOException e) {
    mainForm.append (new StringItem
      ("Copyright", "Sams Publishing; Image not available:" + e));
  }
}

By forcing a new line before and after the image, you ensure that the image is centered in its own line. Figure 3.3 shows the corresponding display on the device. If the image cannot be loaded and an exception is thrown, a simple StringItem is appended to the form instead of the image.

Figure 3.3 The HelloMidp application showing an ImageItem.

Handling Textual Input in TextFields

As shown in Table 3.1, textual input is handled by the class TextField. The constructor of TextField takes four values: a label, initial text, a maximum text size, and constraints that indicate the type of input allowed. In addition to avoiding input of illegal characters, the constraints may also influence the keyboard mode. Several MIDP devices have a numeric keyboard only, and the constraints allow the application manager to switch the key assignments accordingly. The constants listed in Table 3.3, declared in the class TextField, are valid constraint values.

Table 3.3 TextField Constraint Constant Values

Constant

Value

ANY

Allows any text to be added.

EMAILADDR

Adds a valid e-mail address, for instance myemail@mydomain.com.

NUMERIC

Allows integer values.

PASSWORD

Lets the user enter a password, where the entered text is masked.

PHONENUMBER

Lets the user enter a phone number.

URL

Allows a valid URL.


We will now show the usage of TextFields by creating a simple example Form for bank transfers. A bank transfer form contains at least the amount of money to be transferred and the name of the receiver.

To start the implementation of the TeleTransfer MIDlet, you first need to import the two packages containing the midlet and lcdui classes:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

Every MID application is derived from MIDlet, so you need to extend the MIDlet class, too:

public class TeleTransfer extends MIDlet {

Because you want to create a Form that contains Items for entering the transfer information, you need a corresponding member variable mainForm. You can already initialize the variable at its declaration because it has no dependencies from constructor parameters:

Form mainForm = new Form ("TeleTransfer");

In order to let the user enter the transfer information, add TextFields for the name of the receiver for entering the amount to be transferred. Because of the lack of floating-point values in the CLDC, the numeric TextFields in MIDP can hold integer values only. So you need to split the amount into separate fields for dollars and cents. An alternative would be to use an alphanumeric field and parse the string into two separate values. However, this may result in switching the keyboard to alpha mode on cell phones, making numeric input unnecessarily complicated. In this case, you'll limit the size of possible values to five digits for the whole dollar part and two digits for the fractional cent part. Again, you initialize the variables where they are declared:

TextField receiverName = new TextField
  ("Receiver Name", "", 20, TextField.ANY);
TextField receiverAccount = new TextField
  ("Receiver Account#", "", 12, TextField.NUMERIC);
TextField amountWhole = new TextField ("Dollar", "", 6, TextField.NUMERIC);
TextField amountFraction = new TextField ("Cent", "", 2, TextField.NUMERIC);

Finally, you add a variable storing the Display instance for your application:

Display display = Display.getDisplay (this);

Now you can add the constructor to your application where you added the previous TextFields to the main form:

public TeleTransfer () {
  mainForm.append (receiverName);
  mainForm.append (receiverAccount);
  mainForm.append (amountWhole);
  mainForm.append (amountFraction);
}

When the application is started, you request the display to show your money transfer form by calling setCurrent(). As explained in the "MIDlets" section, the application manager notifies you about the application start by calling the startApp() method. So you implement this method accordingly:

public void startApp () {
  display.setCurrent (mainForm);
}

Please note that startApp() is called also when the MIDlet resumes from the paused state, so you cannot move the initialization code from the constructor to this method.

Both pauseApp() and destroyApp() are declared as abstract in the MIDlet class, so you need to implement these methods in your application, even if you do not have real content for them. You just provide empty implementations, like in the HelloMidp example in the first section:

public void pauseApp () {
}

public void destroyApp (boolean unconditional) {
}

Selecting Elements Using ChoiceGroups

In the previous section, you created a simple Form to enter information for transferring money between two accounts. Now you will extend the application to allow the user to select different currencies. For this purpose, you will now add a ChoiceGroup to your application.

The ChoiceGroup is an MIDP UI widget enabling the user to choose between different elements in a Form. These elements consist of simple Strings, but can display an optional image per element as well. ChoiceGroups can be of two different types. Corresponding type constants are defined in the Choice interface. These constants are used in the List class as well; the List class allows an additional third type. The three type constants are listed in Table 3.4.

Table 3.4 Choice Type Constants

Constant

Value

EXCLUSIVE

Specifies a ChoiceGroup or List having only one element selected at the same time.

IMPLICIT

Valid for Lists only. It lets the List send Commands to indicate state changes.

MULTIPLE

In contrast to EXPLICIT, MULTIPLE allows the selection of multiple elements.


The ChoiceGroup constructor requires at least a label and a type value. Additionally, a String array and an Image array containing the elements can be passed to the constructor. Elements can also be added dynamically using the append() method. The append() method has two parameters, a String for the label and an Image. In both cases, the image parameter may be null if no images are desired.

In order to add a ChoiceGroup to the TeleTransfer application, you introduce a new variable currency of type ChoiceGroup. By setting the type to EXCLUSIVE, you get a ChoiceGroup where only one item can be selected at a time. You directly add elements for the United States (USD), the European Union (EUR), and Japan (JPY) by passing a String array created inline. The ChoiceGroup enables the user to choose between three currencies that are represented textually by the abbreviations specified in the String array. The last parameter of the constructor is set to null because you do not want Images to be displayed at this time:

ChoiceGroup currency = new ChoiceGroup
  ("Currency", Choice.EXCLUSIVE,
new String[] {"USD", "EUR", "JPY"}, null);

You still need to add the currency ChoiceGroup to your main Form. As for the text fields, this is done via the append() method of Form:

mainForm.append (currency);

Figure 3.4 shows the TeleTransfer application extended to choose a currency using a ChoiceGroup.

Figure 3.4 The TeleTransfer MIDlet extended to enable the user to choose a currency.

Receiving Changes from Interactive UI Items

If you run the new version of the TeleTransfer MIDlet, you can change the currency using the ChoiceGroup, but the TextField labels for Dollar and Cent are not changed accordingly. You need a way to notify the application if a selection is made in the currency ChoiceGroup.

Receiving changes of interactive high-level UI items in MIDP is based on a listener model similar to AWT. Classes implementing the ItemStateListener interface are able to receive notifications for the following events:

  • State changes of a ChoiceGroup

  • Value adjustments of an interactive Gauge

  • TextField value changes

  • DateField changes

The events are sent to the method itemStateChanged() of the ItemStateListener, where the item that has changed is given as a parameter. In order to actually receive these events, the ItemStateChangeListener must be registered using the setItemStateListener() method of the corresponding Form.

Now that you know about item state change events, you can add the desired functionality to your TeleTransfer MIDlet. First, you need to add the ItemStateListener interface to the class declaration:

public class TeleTransfer extends MIDlet implements ItemStateListener {

You also need to implement a corresponding itemStateChanged() method. Since the itemStateChanged() method is called for changes of all Items in the Form, you need to check the item parameter indicating the event source first. If the source of the event is the currency ChoiceGroup, you set the labels of the amount and fraction TextFields correspondingly:

public void itemStateChanged (Item item) {
  if (item == currency) {
    int index = currency.getSelectedIndex ();
    switch (index) {
    case 0: amountWhole.setLabel ("Dollar");
         amountFraction.setLabel ("Cent");
         break;
    case 1: amountWhole.setLabel ("Euro");
        amountFraction.setLabel ("Cent");
         break;
    case 2: amountWhole.setLabel ("Yen");
        amountFraction.setLabel ("Sen");
      }
    }
  }

Just adding the interface and implementing the corresponding methods is not sufficient to enable the MIDlet to receive state changes. Additionally, you need to register your ItemStateListener at the Form containing the currency item. You do so by calling the setItemStateListener() method in the TeleTransfer constructor:

public TeleTransfer () {
  mainForm.append (senderAccount);
  ...
  mainForm.append (currency);
  mainForm.setItemStateListener (this);
}

Figure 3.5 shows the new version of the TeleTransfer example, where the labels are changed depending on the state of the currency ChoiceGroup.

Figure 3.5 The TeleTransfer MIDlet extended to change the labels depending on the state of the currency ChoiceGroup.

Using Commands for User Interaction

Now you can enter all the information required for a telegraphic transfer, but you have no means to initiate the actual transfer.

In contrast to desktop computers, which have plenty of screen space for displaying buttons or menus, a different approach is necessary for mobile devices. Some devices provide so-called soft buttons, which are buttons without fixed functionality that are assigned dynamically depending on the application context. The number of soft buttons may vary if they are available. Other mobile devices do not even have space for soft buttons, but provide scrolling menus. MIDP needs to abstract from the concrete device and to provide a mechanism that is suitable for all devices, independent of the availability and number of soft buttons. Thus, the lcdui package does not provide buttons or menus, but an abstraction called Command.

Commands can be added to all classes derived from the Displayable class. These classes are Screen and its subclasses such as Form, List, and TextBox for the high-level API and Canvas for the low-level API.

No positioning or layout information is passed to the Command—the Displayable class itself is completely responsible for arranging the visible components corresponding to Commands on a concrete device. The only layout and display information that can be assigned to a Command except from the command label is semantic information. The semantic information consists of a type and a priority. The priority allows the device to decide which commands are displayed as soft buttons if the number of commands exceeds the number of soft buttons available. For additional commands not displayed as soft buttons, a separate menu is created automatically. The type information is an additional hint for the device about how to display the command. For example, if the Exit command is always assigned to the leftmost soft button in native applications of a certain device type, the MIDP implementation is able to make the same assignment. Thus, a consistent look and feel can be accomplished for a device.

The available command type constants are listed in Table 3.5.

Table 3.5 Command Type Constants

Constant

Value

Command.BACK

Used for navigation commands that are used to return the user to the previous Screen.

Command.CANCEL

Needed to notify the screen that a negative answer occurred.

Command.EXIT

Used to specify a Command for exiting the application.

Command.HELP

Passed when the application requests a help screen.

Command.ITEM

A command type to tell the application that it is appended to an explicit item on the screen.

Command.OK

Needed to notify the screen that a positive answer occurred.

Command.SCREEN

A type that specifies a screen-specific Command of the application.

Command.STOP

Interrupts a procedure that is currently running.


The Command constructor takes the label, the command type and the priority as input. The Command class provides read() methods for all these fields, but it is not possible to change the parameters after creation. Using the addCommand() method, commands can be added to a Form or any other subclass of Displayable.

As in the case of receiving state changes of UI widgets, the MIDP uses a listener model for detecting command actions. For this purpose, the lcdui package contains the interface CommandListener. A CommandListener can be registered to any Displayable class using the setCommandListener method. After registration, the method commandAction() of the Commandlistener is invoked whenever the user issues a Command. In contrast to AWT, only one listener is allowed for each Displayable class. The commandAction() callback method provides the Displayable class where the command was issued and the corresponding Command object as parameters.

With this information, you can extend your TeleTransfer application with the desired Commands. But before going into actual command implementation, you need to add some corresponding functionality. You'll add three commands: a Send command, a Clear command, and an Exit command. For Clear, you just add a method setting the content of the fields of your form to empty strings:

public void clear () {
receiverName.setString ("");
receiverAccount.setString ("");
amountWhole.setString ("");
amountFraction.setString ("");
}

The Send command is a bit more difficult since you do not yet have the background to really submit information over the network. (Network connections will be handled in Chapter 6, "Networking: The Generic Connection Framework.") So you just display the content to be transmitted in an alert screen as a temporary replacement:

public void send () {
  Alert alert = new Alert ("Send");
  alert.setString ("transfer " + amountWhole.getString ()
           + "." + amountFraction.getString () + " "
           + amountWhole.getLabel ()
           + "\nto Acc#" + receiverAccount.getString ()
           + "\nof " + receiverName.getString ());
  alert.setTimeout (2000);
  display.setCurrent (alert);
  clear ();
}

For leaving the application, the MIDlet already provides the notifyDestroyed() method, so you do not need to add anything here.

Now that you have implemented the corresponding functionality, the next step is to add the actual Command objects to your application class:

static final Command sendCommand = new Command ("Send", Command.SCREEN, 1);
static final Command clearCommand = new Command ("Clear", Command.SCREEN, 2);
static final Command exitCommand = new Command ("Exit", Command.EXIT, 2);

In order to enable the MIDlet to receive command actions, you need to implement the CommandListener interface, and the corresponding commandAction() method. Depending on the command received, you call send(), clear(), or notifyDestroyed():

public class TeleTransfer extends MIDlet
  implements ItemStateListener, CommandListener {

public void commandAction (Command c, Displayable d) {
  if (c == exitCommand) {
    notifyDestroyed();
  }
  else if (c == sendCommand) {
    send ();
  }
  else if (c == clearCommand) {
    clear ();
  }
}

With these modifications, your TeleTransfer MIDlet is able to handle the desired commands. You still need to add the Commands to the Form, and register the TeleTransfer MIDlet as a CommandListener in order to actually receive the commands:

public TeleTransfer () {
  ...
  mainForm.addCommand (sendCommand);
  mainForm.addCommand (clearCommand);
  mainForm.addCommand (exitCommand);
  mainForm.setCommandListener (this);
}

Figure 3.6 shows the Send Alert of the new version of your TeleTransfer application.

Figure 3.6 The TeleTransfer MIDlet showing an alert that displays the transfer information as a summary before sending.

Further Item Classes: Gauge and DateField

Now you have used all the Item subclasses except Gauge and DateField. Both classes are specialized input elements, where the Gauge may also make sense as a pure read-only information item.

The Gauge item visualizes an integer value by displaying a horizontal bar. It is initialized with a label, a flag indicating whether it is interactive, and a maximum and an initial value. If a Gauge is interactive, the user is allowed to change the value using a device-dependent input method. Changes to the gauge value will cause ItemEvents if a corresponding listener is registered to the form.

The following code snippet shows the construction of a non-interactive Gauge labeled Progress that is initialized with a value of 0 and a maximum of 100:

Gauge gauge = new Gauge ("Progress", false, 0, 100);

If a Gauge is used to display progress of a process that takes a longer amount of time, you should also add a corresponding Stop command to the form to abort the progress.

The current value of the Gauge can be set using the method setValue() and read using the method getValue(). Analogous setMaxValue() and getMaxValue() methods let you access the maximum value of the Gauge.

The DateField is a specialized widget for entering date and time information in a simple way. It can be used to enter a date, a time, or both types of information at once. The appearance of the DateField is specified using three possible input mode constants in the constructor. Possible DateField mode constants are listed in Table 3.6.

Table 3.6 DateField Mode Constants

Constant

Value

DATE

Passed if the DateField should be used for entering a date only.

DATE_TIME

Used for creating a DateField to enter both date and time information.

TIME

Used to enter time information only.


The DateField has two constructors in which a label and the mode can be specified. Using the second constructor, an additional TimeZone can be passed. The following code snippet shows how a DateField for entering the date of birth can be initialized:

DateField dateOfBirth = new DateField ("Date of birth:", DateField.DATE);

After you enter the date into the DateField, it can be accessed using the getDate() method. The DateField offers some additional methods for getting information about the input mode and methods for setting the date and the input mode as well. The concrete usage of the DateField is shown in Chapter 9 in the Blood Sugar Logger application.

Further Screen Classes: List and TextBox

The current version of the TeleTransfer MIDlet shows how to use the Form and the corresponding items available in the lcdui package. The application consists of one main form that holds all application widgets. However, your main form is rather long now, so the question arises how to improve the usability of the application. This section shows how to structure the user interface by using multiple screens and introduces the List and TextBox classes.

The List Class

One possibility to clean up the user interface is to move the currency selection to a separate screen. It takes a lot of space and may need even more room if additional options are added. Also, you can assume that the currency is not changed very often.

You could create a new Form and just move the ChoiceGroup there. However, lcdui provides a special List class inherited from Screen for this purpose. The advantage of the List class is that it provides the IMPLICIT mode that was already mentioned in the section "Selecting Elements Using ChoiceGroups." Using the IMPLICIT mode, the application gets immediate notification when an item is selected. Whenever an element in the List is selected, a Command of the type List.SELECT_COMMAND is issued. As in the ChoiceGroup, the elements consist of Strings and optional Images.

For initializing the List, the lcdui packages offers constructors. The constructors work like the ChoiceGroup constructors. The first one creates an empty List with a given title and type only. The second one takes the title, the type, an array of Strings as initial amount of List elements, and an optional array of Images for each List element. In the implementation of the TeleTransfer application, you implement a new class CurrencyList extending List that will be used as your new currency selector. Since you will use the IMPLICIT mode, you need to implement a command listener, so you can already add the corresponding declaration:

public class CurrencyList extends List implements CommandListener {

To set the labels of the main form TextFields according to the index of the selected element in the CurrencyList, you create two String arrays, CURRENCY_NAMES and CURRENCY_FRACTIONS:

static final String [] CURRENCY_NAMES = {"Dollar", "Euro", "Yen"};
static final String [] CURRENCY_FRACTIONS = {"Cent", "Cent", "Sen"};

In order to set the labels of the main forms TextFields for the whole and the fractional amount according to the selected currency in the CurrencyList, you need a reference back to the main TeleTransfer MIDlet. For this reason, you store the TeleTransfer reference in a variable called teleTransfer. The reference is set in the constructor of your CurrencyList:

TeleTransfer teleTransfer;

In the constructor, you also add currency symbol images to the list. You need to load them, but the call to the super constructor must be the first statement in a constructor. So you call the constructor of the super class by specifying the title and type only. Then you create the Images needed for each list element, which are stored in the MIDlet suite's JAR file. You also call setCommandListener() to register the currency list for handling commands that are issued:

public CurrencyList (TeleTransfer teletransfer) {
  super ("Select Currency", Choice.IMPLICIT);

  this.teleTransfer = teletransfer;

  try {
    append ("USD", Image.createImage ("/Dollar.png"));
    append ("EUR", Image.createImage ("/Euro.png"));
    append ("JPY", Image.createImage ("/Yen.png"));
  }
  catch (java.io.IOException x) {
    throw new RuntimeException ("Images not found");
  }
  setCommandListener (this);
}

The final step in creating the CurrencyList is to implement the commandAction() method of the CommandListener interface. As you already know, a List of IMPLICIT type issues a List.SELECT_COMMAND to the registered CommandListener whenever a new element is selected to indicate the selection change. In case of a selection change, you modify the labels of the main form TextFields. The actual labels are obtained from the String arrays CURRENCY_NAMES and CURRENCY_FRACTIONS. Using the teleTransfer reference, you can access the TextFields. Finally, you call the new method teleTransfer.back(), which sets the screen back to the main form (the back() method will be given at the end of this section):

  public void commandAction (Command c, Displayable d) {
    if (c == List.SELECT_COMMAND) {
      teleTransfer.amountWhole.setLabel
        (CURRENCY_NAMES [getSelectedIndex ()]);
      teleTransfer.amountFraction.setLabel
        (CURRENCY_FRACTIONS [getSelectedIndex ()]);
      teleTransfer.back ();
    }
  }
}

Figure 3.7 shows currency Images and abbreviations in the CurrencyList.

Figure 3.7 The new CurrencyList.

The TextBox Class

Beneath Alert, List, and Form, there is only one further subclass of Screen: the TextBox. The TextBox allows the user to enter multi-line text on a separate screen. The constructor parameters and the constraint constants are identical to those of TextField.

As for the currency list, you can also add a new screen enabling the user to enter a transfer reason if desired. Similar to the CurrencyList, you implement a new class handling the commands related to the new screen. However, this time it is derived from the TextBox. Again, you implement the CommandListener interface:

public class TransferReason extends TextBox implements CommandListener {

In the TextBox, you provide two commands, okCommand for applying the entered text and clearCommand for clearing the text:

static final Command okCommand = new Command ("OK", Command.BACK, 1);
static final Command clearCommand = new Command ("Clear", Command.SCREEN, 2);

Again, you store a reference back to the TeleTransfer MIDlet in the TransferReason TextBox:

TeleTransfer teleTransfer;

The constructor gets the reference back to TeleTransfer MIDlet and stores it in the variable declared previously. You also add the commands to the TextBox, and register it as CommandListener:

public TransferReason (TeleTransfer teleTransfer) {
  super ("Transfer Reason", "", 50, TextField.ANY);
  this.teleTransfer = teleTransfer;

  addCommand (okCommand);
  addCommand (clearCommand);
  setCommandListener (this);
}

Your commandAction() implementation clears the text or returns to the main screen, depending on the Command selected:

  public void commandAction (Command c, Displayable d) {
    if (c == clearCommand) {
      setString ("");
    }
    else if (c == okCommand) {
      teleTransfer.back ();
    }
  }
}

Figure 3.8 shows the TransferReason TextBox.

Figure 3.8 The TransferReason TextBox showing a sample transfer reason text.

TeleTransfer with Multiple Screens

Now you have created two additional screens, but you still need to integrate them in your main application. To do so, you need to change the TeleTransfer implementation somewhat. Since the TeleTransfer's ChoiceGroup for selecting the currency is replaced by the CurrencyList, you do not need the ItemStateListener for detecting item changes any more. So you remove the listener and also the corresponding callback method itemStateChanged(). To display the two new Screens CurrencyList and TransferReason, you implement the two commands currencyCommand and reasonCommand. The new commands are added to the MIDlet in the constructor using the addCommand() method. In the clear() method, the new TextBox is also cleared by calling the corresponding setString() method. Finally you add the back() method to the TeleTransfer application; this method is called from the new Screens to return to the main form. The commandAction() method is extended to handle the new commands, displaying the new Screens. Listing 3.1 shows the complete source code of the final version of the TeleTransfer application.

Listing 3.1 TeleTransfer.java—The Complete TeleTransfer Sample Source Code

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

class CurrencyList extends List implements CommandListener {

  TeleTransfer teleTransfer;
  static final String [] CURRENCY_NAMES = {"Dollar", "Euro", "Yen"};
  static final String [] CURRENCY_FRACTIONS = {"Cent", "Cent", "Sen"};

  public CurrencyList (TeleTransfer teletransfer) {
    super ("Select Currency", Choice.IMPLICIT);

    this.teleTransfer = teletransfer;

    try {
      append ("USD", Image.createImage ("/Dollar.png"));
      append ("EUR", Image.createImage ("/Euro.png"));
      append ("JPY", Image.createImage ("/Yen.png"));
    }
    catch (java.io.IOException x) {
      throw new RuntimeException ("Images not found");
    }
    setCommandListener (this);
  }


  public void commandAction (Command c, Displayable d) {
    if (c == List.SELECT_COMMAND) {
      teleTransfer.amountWhole.setLabel
        (CURRENCY_NAMES [getSelectedIndex ()]);
      teleTransfer.amountFraction.setLabel
        (CURRENCY_FRACTIONS [getSelectedIndex ()]);
      teleTransfer.back ();
    }
  }
}


class TransferReason extends TextBox implements CommandListener {

  static final Command okCommand = new Command ("OK", Command.BACK, 1);
  static final Command clearCommand = new Command
    ("Clear", Command.SCREEN, 2);

  TeleTransfer teleTransfer;

  public TransferReason (TeleTransfer teleTransfer) {
    super ("Transfer Reason", "", 50, TextField.ANY);
    this.teleTransfer = teleTransfer;

    addCommand (okCommand);
    addCommand (clearCommand);
    setCommandListener (this);
  }

  public void commandAction (Command c, Displayable d) {
    if (c == clearCommand) {
      setString ("");
    }
    else if (c == okCommand) {
      teleTransfer.back ();
    }
  }
}

public class TeleTransfer extends MIDlet implements CommandListener {

  static final Command sendCommand = new Command ("Send", Command.SCREEN, 2);
  static final Command clearCommand = new Command
    ("Clear", Command.SCREEN, 2);
  static final Command exitCommand = new Command ("Exit", Command.SCREEN, 1);
  static final Command currencyCommand = new Command
    ("Currency", Command.SCREEN, 2);
  static final Command reasonCommand = new Command
    ("Reason", Command.SCREEN, 2);

  Form mainForm = new Form ("TeleTransfer");

  TextField receiverName = new TextField
    ("Receiver Name", "", 20, TextField.ANY);
  TextField receiverAccount = new TextField
    ("Receiver Account#", "", 8, TextField.NUMERIC);
  TextField amountWhole = new TextField ("Dollar", "", 6, TextField.NUMERIC);
  TextField amountFraction = new TextField
                    ("Cent", "", 2, TextField.NUMERIC);

  CurrencyList currencyList = new CurrencyList (this);
  TransferReason transferReason = new TransferReason (this);
  Display display;

  public TeleTransfer () {
    mainForm.append (receiverName);
    mainForm.append (receiverAccount);
    mainForm.append (amountWhole);
    mainForm.append (amountFraction);

    mainForm.addCommand (currencyCommand);
    mainForm.addCommand (reasonCommand);
    mainForm.addCommand (sendCommand);
    mainForm.addCommand (exitCommand);
    mainForm.setCommandListener (this);
  }

  public void startApp () {
    display = Display.getDisplay (this);
    display.setCurrent (mainForm);
  }

  public void clear () {
    receiverName.setString ("");
    receiverAccount.setString ("");
    amountWhole.setString ("");
    amountFraction.setString ("");
    transferReason.setString ("");
  }

  public void send () {
    Alert alert = new Alert ("Send");
    alert.setString ("transfer " + amountWhole.getString ()
             + "." + amountFraction.getString ()
             + " " + amountWhole.getLabel ()
             + "\nto Acc#" + receiverAccount.getString ()
             + "\nof " + receiverName.getString ());
    alert.setTimeout (2000);
    display.setCurrent (alert);
    clear ();
  }

  public void pauseApp () {
  }

  public void destroyApp (boolean unconditional) {
  }

  public void back () {
    display.setCurrent (mainForm);
  }

  public void commandAction (Command c, Displayable d) {
    if (c == exitCommand) {
      notifyDestroyed();
    }
    else if (c == sendCommand) {
      sendTransferInformation ();
    }
    else if (c == clearCommand) {
      resetTransferInformation ();
    }
    else if (c == currencyCommand) {
      display.setCurrent (currencyList);
    }
    else if (c == reasonCommand) {
      display.setCurrent (transferReason);
    }
  }
}

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020