ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Learning Wireless Java

MIDP GUI Programming, Part 2

Related Reading

Wireless Java
Help for New J2ME Developers
By Qusay Mahmoud

by Qusay Mahmoud

This is the second in a series of articles from O'Reilly's Learning Wireless Java, by Qusay Mahmoud. This section from Chapter 5 focuses on the high-level MIDP GUI APIs and components. You can also read the first excerpt in this series.

The High-Level MIDP APIs

Let's look at how the various classes in the high-level API can be used to create GUI components. We will cover two parts of this process: working with screens and the components that subclass them, and working with forms and the components that can be arranged in them.

Working with Screens

Having seen an example of a screen, a few questions immediately come to mind: how do you manage screens, how do you navigate through them, and how do you manage the display and the input devices? The answer is that all this functionality is implemented by the Display class, which includes methods for requesting that objects be displayed on the device, and for retrieving properties of the device.

Display

A reference to the device's display can be obtained by providing a MIDlet reference to the static getDisplay( ) method.

public static Display getDisplay(MIDlet c);

This is typically done in the startApp( ) method of a MIDlet, as follows:

public class MyMIDlet extends MIDlet {

   Display display = null;

   public MyMIDlet(  ) { // constructor
   }

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

   // other methods
}

TIP: The getDisplay( ) method should be called after the beginning of the MIDlet's startApp( ) method, as shown earlier. It should never be called from the MIDlet's constructor, as per the MIDP specification, as it may not be properly initialized by the application manager at that time.

After you obtain a reference to the device's display, you simply need to create a GUI component to show. Note that all of the GUI components in Figure 5-2 implement the Displayable abstract class. You can pass the GUI component you create to one of Display's two setCurrent( ) methods:

public void setCurrent(Displayable d);
public void setCurrent(Alert alert, Displayable d);

The second method is used when you want to show a temporary alert message followed by the displayable GUI element. We'll discuss alerts later on in this chapter.

To find out what is currently being displayed on the device, use the getCurrent( ) method, which returns a reference to the Displayable object that is currently being displayed.

public Displayable getCurrent(  );

In addition, the Display class (which is really the manager of the device) provides two methods for querying the display to determine the types of colors it supports:

public void boolean inColor(  );
public int numColors(  ); 

The first method, isColor( ), returns a boolean: true if the device supports color and false if it only supports grayscale. The numColors( ) method returns an integer number of distinct colors supported by the device.

Screen

As we mentioned before, the basic unit of interaction between the user and the device is the screen, which is an object that encapsulates device-specific graphics user input. As you can see from the class diagram in Figure 1, there are four types of high-level screens, shown by the subclasses: TextBox, List, Alert, and Form.

Diagram.
Figure 1. Class diagram of the major classes in the lcdui package.

However, Screen is an abstract class with some functionality of its own. Every Screen can have two additional characteristics: a title and a ticker. The screen title is simply a String that appears above the screen contents. The ticker is a graphical component that appears above the title and can be used to scroll information across to the user. Both are optional, although the title will default to a standard string. If the ticker is omitted, it is not shown at all and the space is given instead to the screen. We'll discuss the Ticker component shortly. However, Figure 2 shows the relative positions of the title and the ticker properties in a Screen object.

Diagram.
Figure 2. Titles and tickers on a screen.

The following methods of the Screen class can be used to set and retrieve the title and the ticker, respectively.

public void setTitle(String title);
public String getTitle(  );
public void setTicker(Ticker ticker);
public Ticker getTicker(  );

Ticker

The Ticker class implements a tickertape, or a piece of text that runs continuously across the display. A ticker can be attached to one or more of the four screens discussed earlier, namely: Alert, TextBox, List, and Form. To create a ticker object, use the Ticker constructor:

public Ticker(String str);

You can access the string used in the ticker with the following methods:

public String getString(  );
public void setString(String s);

Once a ticker is created, it can be attached to a screen using the screen's setTicker( ) method. For example, the following snippet of code creates a List screen and attaches a ticker to it:

Display display = Display.getDisplay(  );
List list = new List("Trade Stocks", Choice.EXCLUSIVE);
list.append("Buy", null);
list.append("Sell", null);
list.setTicker(new Ticker("Welcome to my discount broker"));
display.setCurrent(list);

Figure 3 shows what a ticker looks like. It is located above the List component in the display.

Diagram.
Figure 3. An example of a ticker.

There are a few points to note about a ticker:

TextBox

A TextBox object is a screen that allows the user to enter and edit text. You can use a TextBox if your MIDlet needs some kind of input such as a name, a phone number, an email address, or a password. To create a TextBox object, you need to specify four parameters, as shown in the TextBox's constructor:

public TextBox(String title, String text, int maxSize, int constraints);

The title is reused as the screen title, while the text and maxSize are used to determine the initial (or default) text and maximum size of the text box. Finally, constraints can be used to limit the user's input. The constraints used are static constant integers of the TextField class, which are shared between TextField and TextBox, and are as follows:

TextField.ANY
The user is allowed to enter any character.
TextField.EMAILADDR
Input must be an email address.
TextField.NUMBER
Input must be an integer value.
TextField.PASSWD
The text entered will be masked (replaced by asterisks), so the characters typed are not visible.
TextField.PHONENUMBER
Input must be a phone number.
TextField.URL
Input must be a URL.

If you use a constraint other than TextField.ANY, the implementation will perform validation to make sure that the characters that are input conform to the requested type. (For example, TextField.NUMBER will not allow letters to be entered.) This is the only validation that is performed.

Note that the TextField.PASSWD constraint can be combined with any of the other constraints using the bitwise OR "|" operator. For example, if you wanted to create a TextBox that constrained input to a phone number but also wanted to keep the entered data hidden, you would create the object as follows:

TextBox t = new TextBox("Tel", "", 12, TextField.PHONENUMBER |
    TextField.PASSWD);

If you wish to set or retrieve the current constraints that are active for the TextBox, use the following methods:

public int getConstraints(  );
public void setConstrants(int c);

Another thing that we should point out is that a text box has a capacity, or a maximum size, which is the number of characters of text that it can hold. However, each MIDP implementation may place a boundary on the maximum size, which could be smaller than the size the application requested. The maximum size imposed by the implementation can be retrieved using the getMaxSize( ) method and (potentially) reset using the setMaxSize( ) method.

public int getMaxSize(  );
public void setMaxSize(int size);

A well-written MIDP application should always compare the requested size against the current maximum size.

In the current MIDP reference implementation from Sun Microsystems, getMaxSize( ) always returns the requested size by the MIDlet. But don't let that get you out of the habit of checking.

You can set or retrieve the entire text in the TextBox with the setString( ) and getString( ) methods:

public String getString(  );
public void setString(String s);

In addition, if you would like to see the number of characters in the text that has been entered, use the size( ) method, which returns an integer:

public int size(  );

You can also manipulate the text in the TextBox quite easily by deleting, inserting, or replacing the current text using the following methods:

public void delete(int offset, int length);
public void insert(char[] data, int offset, int length, int position);
public void insert(String src, int position);
public void setChars(char[] data, int offset, int length);

Finally, if you want to find out which position the caret, also known as the insertion beam, is currently in front of, TextBox includes the following method:

public int getCaretPosition(  );

Here's a simple example. The following snippet of code creates a TextBox object with the label "TextBox" and initial text set to "This is a text box". The maximum size is 20 characters, which can be any type of characters.

TextBox tb = new TextBox("TextBox", "This is a textbox", 20, TextField.ANY);
Display display = Display.getDisplay(this);
display.setCurrent(tb);

If you write a complete MIDlet and run it in an emulator, you will see something similar to Figure 4. Note that if the text to be displayed is larger than the size of one screen, the implementation will let the user scroll to view and edit any part of the text. How this is done is implementation-dependent.

Diagram.
Figure 4. Relationship between display and screens.


Alert

An alert is an ordinary screen that can contain text and an image. It informs the user about errors and other exceptional conditions. An alert can either be modal or timed.

A modal alert remains on the screen until the user dismisses it, at which point it returns to either the screen that was displayed before it, or a screen specifically chosen by the application. This is useful if you require the user to make a choice. For example, you might display a message such as "Are you sure?" and offer "Yes" and "No" options. Note that a MIDP implementation will automatically provide a way to dismiss a modal alert. Sun's reference implementation, for example, provides a Done command mapped to a soft button.

A timed alert, on the other hand, is displayed for a certain amount of time (typically a few seconds). It is useful for displaying an informative message that does not need to be acknowledged by the user. For example, you might want to display a message that says "Your message has been sent". However, note that if you specify a timed alert that has too much content to be displayed all at once, it automatically becomes a modal alert!

An alert can be created as an instance of the Alert class, which has the following two constructors:

public Alert(String title);
public Alert(String title, String alertText, Image alertImage,
    AlertType alertType);

The first constructor creates a timed alert. However, as you probably noticed, the timeout value is not specified in the constructor. Instead, the alert will use the default timeout value, which can be obtained for each device using the immutable getDefaultTimeout( ) method. If you want to change the alert's timeout, use the setTimeout( ) method with an integer that specifies the timeout in milliseconds. To obtain the current timeout for the alert, use the getTimeout( ) method.

public int getDefaultTimeout(  );
public int getTimeout(  );
public void setTimeout(int t);

For example, the following snippet of code creates a timed alert with a timeout value set to four seconds:

Alert alert = new Alert("title");
alert.setTimeout(4000);

You can also pass in the constant value Alert.FOREVER. This will keep the alert up indefinitely, which has the side effect of turning a timed dialog into a modal dialog.

alert.setTimeout(Alert.FOREVER);

You can create a more specialized alert using the second constructor. This constructor allows you to associate an icon with the alert, using an Image object. Also, an alert may have a type associated with it to provide an indication of the nature of the alert. The MIDP implementation may use this type to play an appropriate sound when the alert is presented to the user. The AlertType class provides five types of alerts: AlertType.ALARM, AlertType.CONFIRMATION, AlertType.ERROR, AlertType.INFO, and AlertType.WARNING. As an example, the following snippet of code creates an alert of type AlertType.CONFIRMATION, and it does not have an icon associated with it:

public Alert(String title, String messageString, Image alertImage,
    AlertType alertType);

Note that any or all of the parameters in the second constructor may be null if you wish to omit the image, the title, the text, or the alert type. The additional properties set in the constructor each has its own set of accessors within the Alert class:

public Image getImage(  );
public String getString(  );
public AlertType getType(  );
public void setImage(Image img);
public void setString(String str);
public void setType(AlertType type);

Now, let's see examples of both timed and modal alerts. The following snippets of code create a TextBox object and a timed alert. When the MIDlet is activated, the alert will be displayed, and after five seconds the text box will be displayed automatically, courtesy of the Display.setCurrent() method.

TextBox tb = new TextBox("text box",
    "Welcome to MIDP GUI Programming", 40, TextField.ANY);
Alert timedAlert = new Alert("Confirmation",
   "Your message has been sent!", null, AlertType.CONFIRMATION);
TimedAlert.setTimeout(5000);
Display display = Display.getDisplay(this);
Display.setCurrent(timedAlert, tb);

Figure 5 shows how the code above is displayed. The alert, which says "Your message has been sent!" is displayed first. After five seconds, the current display returns to the text box that says "Welcome to MIDP GUI Programming."

Diagram.
Figure 5. An example of a timed alert

As you can see from the previous example, timed alerts do not need user intervention. On the other hand, modal alerts stay up until the user dismisses them, as shown in the following example.

TextBox tb = new TextBox("text box", 
     "Welcome to MIDP Programming",
     40, Textfield.ANY);
Alert modalAert = new Alert("Error",
    "Network error. Please try again later.",
     null, AlertType.ERROR);
modalAlert.setTimeout(Alert.FOREVER);
Display display = Display.getDisplay(this);
display.setCurrent(modalAlert, tb);

In this case, the network error screen stays up until the user dismisses it, using the soft button that corresponds to the Done command, as shown in Figure 6. The Done command, for modal alerts, is provided automatically by Sun's MIDP reference implementation. In this example, the text box screen becomes the current screen only after the user dismisses the alert.

Diagram.
Figure 6. An example of a modal alert.

List

A list is a screen containing selectable choices. Both List and ChoiceGroup have common behavior defined by the Choice interface. The user can interact with a list by moving from element to element. Note that this high-level API interaction does not cause any programming events to be fired back to the application. That only occurs when a selection has been made.

A list can be created as an instance of the List class, which has the following two constructors:

public List(String title, int listType);
public List(String title, int listType, String[] stringElements, 
            Image[] imageElements);

The first constructor is used to create an empty list, specifying the title and the type of the list. There are three types of list choices that can be passed in for the second parameter: IMPLICIT, EXCLUSIVE, and MULTIPLE. These options can be specified using the constants provided in the Choice interface, which is implemented by the List class.

As an example, the following snippet of code creates a list of type EXCLUSIVE, the title of which is "Choose one".

List list = new List("Choose one", Choice.EXCLUSIVE);

Once you have created an empty list, you can insert, append, or replace choices in the list. Each choice has an integer index that represents its position in the list. The first choice starts at 0 and extends to the current size of the list minus one. The List class provides the following methods for these operations.

public int append(String stringElement, Image imageElement);
public void insert(int index, String stringElement, Image imageElement);
public void set(int index, String stringElement, Image imageElement);

Note that a choice is composed of a text string and an optional image. For example, here is how to add a couple of choices to the earlier list. Note that the append( ) method returns the index that was assigned to the choice that was passed in, in case we might need it later.

int saveIndex = list.append("save", null);
int deleteIndex = list.append("delete", null);

You can delete any index in the list using the following method:

public void delete(int index);

If you want to retrieve the string element or the image element for any index, the following methods will do the trick:

public String getString(int index);
public Image getImage(int index);

If you want to set, unset, or retrieve the currently selected index in the list, or query any index to see if it is currently selected, use the following methods:

public int getSelectedIndex(  )
public boolean isSelected(int index);
public setSelectedIndex(int index, boolean selected);

Finally, you can use a boolean array to set the selection state of the entire list. This is known as the selection flag, and can be accessed using the following methods. Note that the getSelectedFlags( ) method does not return a boolean array, but instead modifies one that has been passed in (and returns the number of elements that are selected as an integer); this is a common optimization technique that prevents the creation of a new array each time the method is called. The array must be at least as long as the number of elements in the list. If it is longer, then the array elements beyond it are set to false.

public int getSelectedFlags(boolean[] selectedArray);
public void setSelectedFlags(boolean[] selectedArray);

For a list of type MULTIPLE, the setSelectedFlags( ) method sets the selected state of every element in the list. For a list of type EXCLUSIVE or IMPLICIT, exactly one element in the boolean array must be set to true; if no element is true, then the first element will be selected. If two or more elements are true, the implementation chooses the first true element and selects it.

Let's look at some examples of the List component. The following snippet of code shows an example where a list of type EXCLUSIVE is created and displayed:

Display display = Display.getDisplay(this);
List menu = new List("Edit", Choice.EXCLUSIVE);
menu.append("Save");
menu.append("Move to");
menu.append("delete");
display.setCurrent(menu);

In this list, only one choice can be selected, as shown in Figure 7.

Screen shot.
Figure 7. A list of an EXCLUSIVE choice.

If you change the type of the list to IMPLICIT, then the result would be similar to Figure 8. Note that the radio buttons have disappeared.

Diagram.
Figure 8. A list of an IMPLICIT choice.

Similar to an EXCLUSIVE type, only one choice can be selected at a time in this list; however, the focused choice will be implicitly selected, instead of having to select it to color in a circle on the left. The third type of list is MULTIPLE, where multiple selections can be made, as shown in Figure 9.

Diagram.
Figure 9. A list of a MULTIPLE choice.

As we mentioned before, choices in a list are referred to by indices, which are consecutive integers in the range zero to the size of the list, minus 1 (e.g., size( ) - 1). Zero (0) refers to the first choice and size( ) - 1 refers to the last choice. For example, to delete the "Move To" choice in Figure 8:

list.delete(1);

Here, we use the second List constructor to create a list, specifying its title, the type of the list, and an array of strings and images to be used as its initial contents. The following code creates a list with two initial choices and no images:

List list2 = new List("Make a selection", Choice.EXCLUSIVE,
   {"Add", "Delete"}, null);

The number of elements in the list is determined by the length of the stringElements array passed into the constructor, which cannot be null. The imageElements array, however, can be null. However, if it is non-null, it must be the same length as the stringElements array.

Working with Forms

In addition to screen-based components, you also have the ability to use forms to combine multiple components into one screen. This section discusses the Form class as well as the components that can be placed on a form.

Form

A Form object is a screen that contains an arbitrary mixture of items, including read-only and editable text fields, images, date fields, gauges, and choice groups. As we mentioned before, any subclass of the Item class (which we'll discuss shortly) can be placed on a Form object. The Form class has the following two constructors:

public Form(String title);
public Form(String title, Item[] items);

The first constructor is used to create a new empty form, specifying only its title. The second constructor is used to create a new form with a title and initial contents. As an example, the following line of code creates an empty form that has the title "Choose an Item", as shown in Figure 10. This is basically a regular screen.

Screen shot.
Figure 10. An empty form.

Form form = new Form("Choose an Item");

The Form object does not use any sort of layout manager. Instead, the Form object will arrange its components much like a list, usually top to bottom. And like the choices within a list, items within a form can be edited using appropriate operations such as insert, append, and delete. The methods of the Form class, along with their signatures, are listed below.

First, to append an image to the end of the form, you can use the following method:

public int append(Image img);

This method appends an object that subclasses the Item object:

public int append(Item item);

You can also append a generic string, using the following method:

public int append(String str);

This method deletes the item at the given position in the form, shrinking the size of the form by one.

public void delete(int itemNum):

You can access any item in the form at its given position using the following method. The contents of the form will be left unchanged.

public Item get(int itemNum);

This method inserts an item in the form just prior to the index specified:

public void insert(int itemNum, Item item);

The following method replaces the previous item by setting the item referenced by itemNum to the specified Item given:

public int set(int itemNum, Item item);

Finally, in order to find the current number of items that are in the form, use the size( ) method:

public int size(  );

The GUI components that can be placed on a form are the following: ChoiceGroup, DateField, Gauge, ImageItem, StringItem, and TextField. All of these items are subclasses of the Item abstract class. We will see how to place these items on a form shortly. But first, let's introduce each one in turn.

Item

The Item abstract class acts as the base class for all components that can be placed either on a form or an alert. All Item objects have a label (i.e., a string attached to the item), which can be accessed using the following methods:

public String getLabel(  );
public void setLabel(String s);

These are the only two methods in this abstract class.

ChoiceGroup

A ChoiceGroup object represents a group of selectable choices to be placed on a Form object. Similar to the List class, it implements the Choice interface. It also extends the Item abstract class. This object may mandate that a single choice be made, or it may allow multiple choices. The ChoiceGroup class has the following two constructors:

public ChoiceGroup(String label, int choiceType);
public ChoiceGroup(String label, int choiceType,
    String[] stringElements, Image[] imageElements);

The first constructor is used to create an empty choice group, specifying its label and type. Since this class implements the Choice interface, you might think that there are three types of choices you can use. However, when using a choice group, only two choices are available: EXCLUSIVE and MULTIPLE. The IMPLICIT type is not available for use with a choice group, like it was with the List component. There is no need to have a "menu" like choice field inside of a form. (Remember that EXCLUSIVE is a choice having exactly one choice selected at a time; and MULTIPLE is a choice that can have an arbitrary number of choices selected at a time.)

The second ChoiceGroup constructor can be used to create a new choice group, specifying its title and type, as well as an array of strings and images to be used as its initial contents.

Once you have created an empty choice, you can insert, append, or replace choices in it, exactly as in a List component. Again, each choice has an integer index that represents its position in the list. The first choice starts at 0 and extends to the current size of the list, minus one. The ChoiceGroup class provides the following methods for these operations.

public int append(String stringElement, Image imageElement);
public void insert(int index, String stringElement, Image imageElement);
public void set(int index, String stringElement, Image imageElement);

Note that a choice is composed of a text string and an optional image. For example, here is how to add a couple of choices to the earlier list. Note that the append( ) method returns the index that was assigned to the choice that was passed in, in case we might need it later.

int saveIndex = list.append("save", null);
int deleteIndex = list.append("delete", null);

In addition, you can delete any index in the choice group using the following method:

public void delete(int index);

If you want to retrieve the string element or the image element for any index, the following methods are useful:

public String getString(int index);
public Image getImage(int index);

If you want to set, unset, or retrieve the currently selected index in the choice group, or query any index to see if it is currently selected, use the following:

public int getSelectedIndex(  )
public boolean isSelected(int index);
public setSelectedIndex(int index, boolean selected);

Finally, just as with the List component, you can use a boolean selection flags array to set the selection state of the entire choice group. Again, the getSelectedFlags( ) method does not return a boolean array, but instead modifies one that has been passed in (and returns the number of elements that are selected as an integer as an optimization technique). The array must be at least as long as the number of elements in the list. If it is longer, then the array elements beyond it are set to false.

public int getSelectedFlags(boolean[] selectedArray);
public void setSelectedFlags(boolean[] selectedArray);

For a list of type MULTIPLE, the setSelectedFlags( ) method sets the selected state of every element in the list. For a list of type EXCLUSIVE, exactly one element in the boolean array must be set to true; if no element is true, then the first element will be selected. If two or more elements are true, the implementation chooses the first true element and selects it.

The following snippet of code creates a new empty ChoiceGroup object whose title is "Selection", and whose type is EXCLUSIVE:

ChoiceGroup choices = new ChoiceGroup("Method of payment", Choice.EXCLUSIVE);

The following code adds several new choices to the choice group.

choices.append("Visa", null);
choices.append("Master Card", null);
choices.append("Amex", null);

Similar to choices within a list, choices within a choice group can be edited using the familiar insert, append, and delete methods. In addition, choices are referred to by their indexes. For example, to delete the last choice:

choices.delete(2);

It is important to note that once a choice group has been created and populated, it cannot be displayed using setCurrent( ), as a list can. A choice group is a subclass of item and has to be placed on a form, which can in turn be displayed using setCurrent( ).

Form form = new Form("Choose one");
form.append(choices);
Display.setCurrent(form);

Figure 11 shows an example of an EXCLUSIVE choice group, and Figure 12 shows an example of a MULTIPLE choice group. Again, the IMPLICIT choice is not available for use with the ChoiceGroup class; if you attempt to use it, an IllegalArgumentException will be thrown.

Screen shot.
Figure 11. An EXCLUSIVE choice group.

Screen shot.
Figure 5-13. A MULTIPLE choice group.

DateField

A DateField object is an editable component for representing calendar date and time information that can be placed on a Form object. It can be configured to accept date or time information, or both. A DateField object can be created using one of the following two constructors:

public DateField(String label, int mode);
public DateField(String label, int mode, TimeZone timeZone);

The first constructor is used to create a DateField object with the specified label and mode. This mode can be specified providing one of the static fields: DateField.DATE, DateField.TIME, or DateField.DATE_TIME. The DateField.DATE input mode allows you to set date information, DateField.TIME allows for clock time information (hours and minutes), and DateField.DATE_TIME allows for setting both.

The DateField object has the following methods to access the properties added onto the Form object (remember that the label property is defined in the Item abstract class):

public Date getDate(  )
public int getInputMode(  )
public void setDate(Date date);
public void setInputMode(int mode);

In addition, you can use the toString( ) method to output a string-based copy of the date or time data.

public String toString(  );

As an example, the following code creates a DateField object with the label as "Today's date" and the mode as DateField.DATE:

DateField date = new DateField("Today's date", DateField.DATE);

To display a date field, first create a Form object, and then use the append( ) method of the form to add the date field.

Form form = new Form("Date Info");
form.append(date);
Display.setCurrent(form);

In this example, since the DATE input mode is selected, the MIDlet would display a <date> item for the user to select, as shown in Figure 13. Once selected, it will display the current calendar date, and you should be able to set a new date.

Screen shot.
Figure 13. A date field representing the calendar date.

If the DateField.TIME input mode is used, the MIDlet would display a <time> item for the user to select, as shown in Figure 14. Once selected, the current clock time information will be displayed, and you can likewise set a new time.

Screen shot.
Figure 14. A date field representing clock time information.

Finally, if the DateField.DATE_TIME input mode is used, the MIDlet would display the items <date> and <time> and you would be allowed to choose one at a time.

Note that you can initialize the date and time before displaying the component. You can do so using the following snippet of code:

d = new DateField("Today: ", DateField.DATE);
d.setDate(new Date(  ));
form = new Form("Date & Time");
form.append(d);    display.setCurrent(form);

At this point, the date field displays the current date and time, as shown in Figure 15.

Screen shot.
Figure 15. A date field represented with the DATE_TIME constant.

The second DateField constructor is used to create a date field specifying its label, input mode, and time zone information. For example, the following snippet of code creates a DateField object where the time zone is GMT:

DateField date = new DateField("date", DateField.DATE,
                               TimeZone.getTimeZone("GMT"));

If the TimeZone field is null, the default time zone (based on the time zone where the program is running) is used. Hence, the following two lines of code do exactly the same thing:

DateField date1 = new DateField("date", DateField.DATE);
DateField date2 = new DateField("date", DateField.DATE, TimeZone.getDefault( ));

The TimeZone class is part of the java.util package, which has been inherited from the J2SE.

Gauge

A Gauge object represents a bar graph display that can be used within a form. The Gauge class has the following constructor:

public Gauge(String label, boolean interactive, int maxValue, int initialValue);

This constructor is used to create a new Gauge object with the given label, in interactive or non-interactive mode, with the given maximum and initial values. In interactive mode, the user is allowed to modify the gauge's current value; in non-interactive mode, the user is not allowed to change the value at all (e.g., what you might see in a progress bar). You can query whether the gauge is currently in interactive mode with the following method:

public boolean isInteractive(  );

The Gauge object also provides the following methods to access the current value and maximum value properties that we saw in the constructor:

public int getMaxValue(  );
public int getValue(  );
public void setMaxValue(int maxValue);
public void setValue(int value);

A gauge will always maintain a current value between zero and the maximum value specified. For example, the following snippet of code creates an interactive gauge where the maximum value is 20 and the initial value is 0:

Gauge gauge = new Gauge("graph", true, 20, 0);

Once a Gauge object is created, it can be placed on a Form component, like the other components that we've seen:

Form form = new Form("item");
form.append(gauge);

This interactive gauge is shown in Figure 16. Note that the style of the gauge is of an ascending arc from right to left, as you might see on a LED volume control.

Screen shot.
Figure 16. An example of an interactive gauge.

If the gauge is used to reflect progress, the application will need to keep updating it. In this case, it will need to keep a reference to it handy and repeatedly call setValue( ) to reflect the current progress.

The following snippet of code shows an example of a non-interactive gauge that reflects a progress bar:

Display display = Display.getDisplay(this);
Gauge progressbar = new Gauge("Progress", false, 20, 9);
Form form = new Form("Configuring App);
form.append(progressbar);

This progress bar is shown in Figure 17. Note here that the non-interactive form of a gauge is level from right to left.

Screen shot.
Figure 17. A non-interactive gauge representing a progress bar.


Image and ImageItem

An ImageItem object is an image component that contains a reference to an Image object. First, let's briefly introduce the Image class. We will revisit it again later when we talk about low-level APIs.

The Image class is used as a graphical image data holder. Depending on how they are created, images can either be immutable or mutable. Immutable images are generally created by loading image data from resource bundles, from files, or across a network. Once they are created, they may not be modified. Mutable images, on the other hand, are created in off-screen memory and can be modified.

Images that are to be placed within an Alert, Form, or ImageItem must be immutable, since the implementation will use them to update the display without notifying the application. Otherwise, the containing Alert or Form would have to be updated on every graphics call.

A mutable image can be created using one of the static createImage( ) methods of the Image class.

public static Image createImage(int width, int height);

The other three static createImage( ) methods are used to create immutable images:

public static Image createImage(Image image);
public static Image createImage(String name);
public static Image createImage(byte[] imageData, int imageOffset, 
    int imageLength);

Here is an example of creating an immutable image from a graphics file:

Image image = Image.createImage("/Duke.png");

This image can then be placed on a Form object in the typical fashion:

Form form = new Form("Duke");
form.append(image);

Note that the graphics file has the extension png. This acronym stands for Portable Network Graphics. All MIDP implementations are required to support images stored in at least Version 1.0 of PNG. As of this writing, no other graphics formats are accepted. Also, if you're using the emulator within J2ME Wireless Toolkit's KToolbar application, note that the reference to Duke using /duke.png means that the Duke is in the res directory, c:\j2mewtk\apps\Myproject\res. Figure 18 depicts the screen shown with this example.

Screen shot.
Figure 18. Placing an Image object on a form.

The Image class has a few methods that can come in handy to discover the height, width, and mutable status of any image:

public int getHeight(  );
public int getWidth(  );
public boolean isMutable(  );

In addition, if the image is mutable, you can obtain a Graphics object of the image using the following method. (We'll cover this in much more detail when we discuss the low-level graphics API.)

public Graphics getGraphics(  );

Now, let's see how to use the ImageItem class, which provides control and layout when Image objects are added to a form or an alert. To create an ImageItem object, use the ImageItem constructor:

public ImageItem(String label, Image img, int layout,
     String altText);

This constructor is used to create a new immutable ImageItem object with a given label, image, layout directive, and alternative text string. The altText parameter specifies a string to be displayed in place of the image if it exceeds the capacity of the display. The layout parameter is a combination of the following values, which are static field members of the ImageItem class:

ImageItem.LAYOUT_CENTER
The image should be horizontally centered.
ImageItem.LAYOUT_DEFAULT
You should use the default formatting of the container of the image.
ImageItem.LAYOUT_LEFT
The image should be close to the left edge of the drawing area.
ImageItem.LAYOUT_NEWLINE_AFTER
A new line should be started after the image is drawn.
ImageItem.LAYOUT_NEWLINE_BEFORE
A new line should be started before the image is drawn.
ImageItem.LAYOUT_RIGHT
The image should be close to the right edge of the drawing area.

There are some rules on how the above layout values can be combined:

TIP:  The layout directives serve merely as a hint, but it may be ignored by the implementation. Such is the case with Sun's MIDP reference implementation.

The ImageItem class also contains the following methods to access the properties that we just saw in the constructor:

public String getAltText(  );
public Image getImage(  );
public int getLayout(  );
public void setAltText(String altText);
public void setImage(Image img);
public void setLayout(int layout);

So, to create an ImageItem object, use the above ImageItem constructor:

Image img = Image.createImage("/Duke.png");
ImageItem imageItem = new ImageItem("Image", img,
    ImageItem.LAYOUT_CENTER, "img");
 
Form form = new Form("Duke");
form.append(imageItem);

This example would produce a screen similar to that in Figure 18, except that this one would have a title for the ImageItem object.

StringItem

A StringItem object is a text component item that may contain a string that cannot be edited by the user. A StringItem has a label that can be modified by the application. The contents of StringItem can be modified by the application as well. Here is the constructor:

public StringItem(String label, String contents);

Creating a StringItem object is easy:

StringItem si = new StringItem("label", "contents");

The setText() and getText( ) methods are used to set and get the StringItem contents; the setLabel() and getLabel( ) methods, which are defined in the Item abstract class, are used to set and get the label of the StringItem:

public void setText(String s);
public void setLabel(String l);
public String getText(  );
public String getLabel(  );

The following snippet of code creates a StringItem object and places it within a Form object. The form is then set to be the current screen, as shown in Figure 19.

Screen shot.
Figure 19. The user cannot edit the contents of a StringItem object.

Display display = display.getDisplay(this);
StringItem si = new StringItem("String item:\n", "Hello World!");
Form form = new Form("Greetings");
form.append(si);
display.setCurrent(form);

Related Reading

Learning Wireless JavaLearning Wireless Java
By Qusay H. Mahmoud
Table of Contents
Index
Sample Chapter
Full Description

TextField

Unlike StringItem, a TextField object is an editable text component that may be placed on a Form. Similar to a TextBox, however, a TextField has a capacity (or a maximum size), which is the number of characters that can be stored in the object. Again, the MIDP implementation may place a boundary on the maximum size, which could be smaller than the size the application requested. The maximum size imposed by the implementation can be retrieved using getMaxSize( ). But, as mentioned earlier, in Sun's MIDP reference implementation, the getMaxSize( ) method returns the size requested by the application.

Use a TextField object if your MIDlet requires input from the user. A TextField object can be created as an instance of the TextField class, which has the following constructor:

public TextField(String label, String text, int maxSize, int
    constraints);

This constructor is used to create a new TextField object with the given label, initial contents, maximum size in characters, and constraints. The constraints field is used to limit the user's input. The constraints are the TextField's static constants, which are shared with TextBox as discussed earlier, and they are: TextField.ANY, TextField.EMAILADDR, TextField.NUMBER, TextField.PASSWD, TextField.PHONENUMBER, and TextField.URL. Again, if you use a constraint other than TextField.ANY, the TextField will perform a simple validation to make sure that the characters that are input are of the requested type.

If you wish to set or retrieve the current constraints that are active for the TextField, use the following methods:

public int getConstraints(  );
public void setConstrants(int c);

The maximum size imposed by the implementation can be retrieved using the getMaxSize( ) method, and (potentially) reset using the setMaxSize( ) method.

public int getMaxSize(  );
public void setMaxSize(int size);

You can set or retrieve the entire text in the TextField with the setString( ) and getString( ) methods:

public String getString(  );
public void setString(String s);

In addition, if you would like to see the number of characters in the text that has been entered, use the size( ) method, which returns an integer:

public int size(  );

The methods to delete, insert, or replace the current text are identical to TextBox:

public void delete(int offset, int length);
public void insert(char[] data, int offset, int length, int position);
public void insert(String src, int position);
public void setChars(char[] data, int offset, int length);

Finally, if you want to find out which position the caret, also known as the insertion beam, is currently in front of, TextField includes the following method:

public int getCaretPosition(  );

The following code shows this component in action. It creates a login form with two text fields, one for loginID and the other for the password. Once started, you can enter your username and a password, as shown in Figure 20.

Screen shot.
Figure 20. Example of TextField.

Display display = Display.getDisplay(this);
TextField userName = new TextField("LoginID:", "", 10,
    TextField.ANY);
TextField password = new TextField("Password:", "", 10,
    TextField.PASSWORD);
Form form = new Form("Sign in");
form.append(userName);
form.append(password);
display.setCurrent(form);

In next week's final installment from this chapter, you'll learn how to create Low-Level GUI Components.


Read the first excerpt in this series.

View catalog information for Learning Wireless Java


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.