MIDP Programming with J2ME
December 26, 2002
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.javaThe 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);
}
}
}