|
|
|
|
Learning Wireless JavaHelp for New J2ME DevelopersQusay H. MahmoudDecember 2001 0-59600-243-2, Order Number: 2432 262 pages, $34.95 |
Chapter 5
MIDP GUI ProgrammingUser interface requirements for handheld devices are different from those for desktop computers. For example, the display size of handheld devices is smaller, and input devices do not always include pointing tools such as a mouse or pen input. For these reasons, you cannot follow the same user-interface programming guidelines for applications running on handheld devices that you can on desktop computers.
The CLDC itself does not define any GUI functionality. Instead, the official GUI classes for the J2ME are included in profiles such as the MIDP and are defined by the Java Community Process (JCP). You'll note that the GUI classes included in the MIDP are not based on the Abstract Window Toolkit (AWT). That seems like a major issue, which brings us to the following question.
Why Not Reuse the AWT?
After a great deal of consideration, the MIDP Expert Group decided not to subset the existing AWT and Project Swing classes for the following reasons:
- AWT is designed for desktop computers and optimized for these machines.
- AWT assumes certain user interaction models. The component set of the AWT is designed to work with a pointing device such as a mouse; however, many handheld devices, such as cell phones, have only a keypad for user input.
- AWT has a rich feature set, and includes support for functionality that is not found or is impractical to implement on handheld devices. For example, the AWT has extensive support for window management, such as resizing overlapping windows. However, the limited display size of handheld devices makes resizing a window impractical. Therefore, the window and layout managers within the AWT are not required for handheld devices.
- When a user interacts with an AWT-based application, event objects are created dynamically. These objects exist only until each associated event is processed by the application or system, at which time the object becomes eligible for garbage collection. The limited CPU and memory of handheld devices, however, cannot handle the burden.
The MIDP GUI APIs
Because of the issues outlined earlier, the MIDP contains its own abbreviated GUI, which is much different from AWT. The MIDP GUI consists of both high-level and low-level APIs, each with their own set of events. This chapter discusses and shows examples of using objects from both the high-level and low-level APIs. Handling events from APIs, however, is deferred to the next chapter.
The high-level API is designed for applications where portability between mobile information devices is important. To achieve portability, the API employs a high-level abstraction and gives you little control over its look and feel. For example, you cannot define the visual appearance (shape, color, or font) of the high-level components. Most interactions with the components are encapsulated by the implementation; the application will not be aware of them. Consequently, the underlying implementation does the necessary adaptation to the device's hardware and native user interface style. Classes that implement the high-level API all inherit the
javax.microedition.lcdui.Screenclass.The low-level API provides little abstraction. It is designed for applications that need precise placement and control of graphic elements, as well as access to low-level input events. This API gives the application full control over what is being drawn on the display. The
javax.microedition.lcdui.Canvasandjavax.microedition.lcdui.Graphicsclasses implement the low-level API. However, we should point out that MIDlets that access the low-level API are not guaranteed to be portable, because this API provides mechanisms to access details that are specific to a particular device.The MIDP GUI Model
Here's how the MIDP GUI model works, in a nutshell. In order to show something on a MIDP device, you'll need to obtain the device's display, which is represented by the
javax.microedition.lcdui.Displayclass. TheDisplayclass is the one and only display manager that is instantiated for each active MIDlet and provides methods to retrieve information about the device's display capabilities.Obtaining the
device's display is easy. However, this object by itself isn't very interesting. Instead, the more interesting abstraction is the screen, which encapsulates and organizes graphics objects and coordinates user input through the device. Screens are represented by thejavax.microedition.lcdui.Screenobject and are shown by theDisplayobject by calling itssetCurrent( )method. There can be several screens in an application, but only one screen at a time can be visible (or current) in a display, and the user can traverse only through the items on that screen. Figure 5-1 shows the one-to-many relationship between the display and its screens.
Figure 5-1. Relationship between display and screens ![]()
There are three types of screens in the MIDP GUI:
- Screens that entirely encapsulate a complex user interface component, such as a
ListorTextBoxcomponent (theListcomponent is shown in Figure 5-8 and theTextBoxcomponent is shown in Figure 5-5). The structure of these screens is predefined, and the application cannot add other components to these screens.
- Generic screens that use a
Formcomponent. The application can add text, images, and a simple set of related UI components to the form, which acts as a container.
- Screens used within the context of the low-level API, such as a subclass of the
CanvasorGraphicsclass.The lcdui Package
All MIDP GUI classes are contained in the
javax.microedition.lcduipackage. This package contains three interfaces and twenty-one classes, as shown in Table 5-1 and Table 5-2.
Table 5-1: lcdui interfaces Interface
Description
ChoiceDefines an API for a user interface component that implements a selection from a predefined number of choices
CommandListenerUsed by applications that need to receive high-level events from implementations
ItemStateListenerUsed by applications that need to receive events that indicate changes in the internal state of the interactive items
Table 5-2: lcdui classes Class
Description
AlertA screen that shows data to the user and waits for a certain period of time before proceeding to the next screen.
AlertTypeA utility class that indicates the nature of the alert.
CanvasThe base class for writing applications that need to handle low-level events and to issue graphics calls for drawing to the display.
ChoiceGroupA group of selectable elements intended to be placed within a
Form.
CommandA construct that encapsulates the semantic information of an action.
DateFieldAn editable component for presenting calendar data and time information that may be placed into a
Form.
DisplayA utility that represents the manager of the display and input devices of the system.
DisplayableAn object that has the capability of being placed on the display.
FontA utility that represents font and font metrics.
FormA screen that contains an arbitrary mixture of items (images, text, text fields, or choice groups, for instance).
GaugeA utility that implements a bar graph display of a value intended for use in a form.
GraphicsA utility that provides a simple two-dimensional geometric rendering capability.
ImageA utility that holds graphical image data.
ImageItemA utility that provides layout control when
Imageobjects are added to a form or alert.
ItemA superclass for all components that can be added to a
FormorAlert.
ListA screen containing a list of choices.
ScreenThe superclass of all high-level user interface classes.
StringItemAn item that can contain a
String.
TextBoxA screen that allows the user to enter and edit text.
TextFieldAn editable text component that can be placed into a
Form.
TickerA ticker-type piece of text that runs continuously across the display. It can be attached to all screen types except
Canvas.The class diagram in Figure 5-2 shows the major classes and the relationships between them.
Figure 5-2. Class diagram of the major classes in the lcdui package ![]()
The High-Level MIDP APIs
Now, let's see 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
Displayclass, 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 thestatic 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: ThegetDisplay( )method should be called after the beginning of the MIDlet'sstartApp( )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
Displayableabstract class. You can pass the GUI component you create to one ofDisplay's twosetCurrent( )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 theDisplayableobject that is currently being displayed.public Displayable getCurrent( );In addition, the
Displayclass (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:trueif the device supports color andfalseif it only supports grayscale. ThenumColors( )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 5-2, there are four types of high-level screens, shown by the subclasses:TextBox,List,Alert, andForm.However,
Screenis an abstract class with some functionality of its own. EveryScreencan have two additional characteristics: a title and a ticker. The screen title is simply aStringthat 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 theTickercomponent shortly. However, Figure 5-3 shows the relative positions of the title and the ticker properties in aScreenobject.
Figure 5-3. Titles and tickers on a screen ![]()
The following methods of the
Screenclass 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
Tickerclass 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, andForm. To create a ticker object, use theTickerconstructor: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 aListscreen 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 5-4 shows what a ticker looks like. It is located above the
Listcomponent in the display.
Figure 5-4. An example of a ticker ![]()
There are a few points to note about a ticker:
- No method calls are provided for starting and stopping the ticker.
- The ticker string scrolls continuously. In other words, when the string finishes scrolling off the display, the ticker starts over at the beginning of the string. It may help to add some spaces at the end of the ticker string so the message ends do not appear tied together.
- The direction and the speed of the scrolling are determined by the MIDP implementation.
TextBox
A
TextBoxobject is a screen that allows the user to enter and edit text. You can use aTextBoxif your MIDlet needs some kind of input such as a name, a phone number, an email address, or a password. To create aTextBoxobject, you need to specify four parameters, as shown in theTextBox's constructor:public TextBox(String title, String text, int maxSize, int constraints);The
titleis reused as the screen title, while thetextandmaxSizeare 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 theTextFieldclass, which are shared betweenTextFieldandTextBox, 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.NUMBERwill not allow letters to be entered.) This is the only validation that is performed.Note that the
TextField.PASSWDconstraint can be combined with any of the other constraints using the bitwise OR "|" operator. For example, if you wanted to create aTextBoxthat 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 thesetMaxSize( )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
TextBoxwith thesetString( )andgetString( )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
TextBoxquite 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,
TextBoxincludes the following method:public int getCaretPosition( );Here's a simple example. The following snippet of code creates a
TextBoxobject 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 5-5. 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.
Figure 5-5. A TextBox example ![]()
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
Donecommand 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
Alertclass, 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 thesetTimeout( )method with an integer that specifies the timeout in milliseconds. To obtain the current timeout for the alert, use thegetTimeout( )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
Imageobject. 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. TheAlertTypeclass provides five types of alerts:AlertType.ALARM,AlertType.CONFIRMATION,AlertType.ERROR,AlertType.INFO, andAlertType.WARNING. As an example, the following snippet of code creates an alert of typeAlertType.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
Alertclass: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
TextBoxobject 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 theDisplay.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-6 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."
Figure 5-6. 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
Donecommand, as shown in Figure 5-7. TheDonecommand, 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 thealert.
Figure 5-7. An example of a modal alert ![]()
List
A
list is a screen containing selectable choices. BothListandChoiceGrouphave common behavior defined by theChoiceinterface. 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
Listclass, 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, andMULTIPLE. These options can be specified using the constants provided in theChoiceinterface, which is implemented by theListclass.
- An
EXCLUSIVEtype of list has no more than one choice selected at a time, which is similar to a group of radio buttons in the AWT world.
- An
IMPLICITtype is anEXCLUSIVEchoice where the focused choice is implicitly selected, much like a drop-down menu.
- The
MULTIPLEtype is a list that can have arbitrary number of choices selected at a time, and presents itself as a series of checkboxes.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
Listclass 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 tofalse.public int getSelectedFlags(boolean[] selectedArray);public void setSelectedFlags(boolean[] selectedArray);For a list of type
MULTIPLE, thesetSelectedFlags( )method sets the selected state of every element in the list. For a list of typeEXCLUSIVEorIMPLICIT, exactly one element in the boolean array must be set totrue; if no element istrue, then the first element will be selected. If two or more elements aretrue, the implementation chooses the first true element and selects it.Let's look at some examples of the
Listcomponent. The following snippet of code shows an example where a list of typeEXCLUSIVEis 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 5-8.
Figure 5-8. A list of an EXCLUSIVE choice ![]()
If you change the type of the list to
IMPLICIT, then the result would be similar to Figure 5-9. Note that the radio buttons have disappeared.
Figure 5-9. A list of an IMPLICIT choice ![]()
Similar to an
EXCLUSIVEtype, 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 isMULTIPLE, where multiple selections can be made, as shown in Figure 5-10.
Figure 5-10. 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 andsize( ) - 1refers to the last choice. For example, to delete the "Move To" choice in Figure 5-9:list.delete(1);Here, we use the second
Listconstructor 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
stringElementsarray passed into the constructor, which cannot benull. TheimageElementsarray, however, can be null. However, if it is non-null, it must bethesamelength as thestringElementsarray.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
Formclass as well as the components that can be placed on a form.Form
A
Formobject 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 theItemclass (which we'll discuss shortly) can be placed on aFormobject. TheFormclass 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 5-11. This is basically a regular screen.
Figure 5-11. An empty form ![]()
Form form = new Form("Choose an Item");The
Formobject does not use any sort of layout manager. Instead, theFormobject 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 theFormclass, 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
Itemobject: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
itemNumto the specifiedItemgiven:public int set(int itemNum, Item item);Finally, in order to
find the current number of items that are in the form, use thesize( )method:public int size( );The GUI components that can be placed on a form are the following:
ChoiceGroup,DateField,Gauge,ImageItem,StringItem, andTextField. All of these items are subclasses of theItemabstract class. We will see how to place these items on a form shortly. But first, let's introduce each one inturn.Item
The
Itemabstract class acts as the base class for all components that can be placed either on a form or an alert. AllItemobjects 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
ChoiceGroupobjectrepresents a group of selectable choices to be placed on aFormobject. Similar to theListclass, it implements theChoiceinterface. It also extends theItemabstract class. This object may mandate that a single choice be made, or it may allow multiple choices. TheChoiceGroupclass 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
Choiceinterface, you might think that there are three types of choices you can use. However, when using a choice group, only two choices are available:EXCLUSIVEandMULTIPLE. TheIMPLICITtype is not available for use with a choice group, like it was with theListcomponent. There is no need to have a "menu" like choice field inside of a form. (Remember thatEXCLUSIVEis a choice having exactly one choice selected at a time; andMULTIPLEis a choice that can have an arbitrary number of choices selected at a time.)The second
ChoiceGroupconstructor 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
Listcomponent. 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. TheChoiceGroupclass 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
Listcomponent, you can use a boolean selection flags array to set the selection state of the entire choice group. Again, thegetSelectedFlags( )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 tofalse.public int getSelectedFlags(boolean[] selectedArray);public void setSelectedFlags(boolean[] selectedArray);For a list of type
MULTIPLE, thesetSelectedFlags( )method sets the selected state of every element in the list. For a list of typeEXCLUSIVE, exactly one element in the boolean array must be set totrue; if no element istrue, then the first element will be selected. If two or more elements aretrue, the implementation chooses the firsttrueelement and selects it.The following snippet of code creates a new empty
ChoiceGroupobject whose title is "Selection", and whose type isEXCLUSIVE: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 usingsetCurrent( ).Form form = new Form("Choose one");form.append(choices);Display.setCurrent(form);Figure 5-12 shows an example of an
EXCLUSIVEchoice group, and Figure 5-13 shows an example of aMULTIPLEchoice group. Again, theIMPLICITchoice is not available for use with theChoiceGroupclass; if you attempt to use it, anIllegalArgumentExceptionwill be thrown.
Figure 5-12. An EXCLUSIVE choice group![]()
Figure 5-13. A MULTIPLE choicegroup![]()
DateField
A
DateFieldobject is an editable component for representing calendar date and time information that can be placed on aFormobject. It can be configured to accept date or time information, or both. ADateFieldobject 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
DateFieldobject with the specified label and mode. This mode can be specified providing one of the static fields:DateField.DATE,DateField.TIME, orDateField.DATE_TIME. TheDateField.DATEinput mode allows you to set date information,DateField.TIMEallows for clock time information (hours and minutes), andDateField.DATE_TIMEallows for setting both.The
DateFieldobject has the following methods to access the properties added onto theFormobject (remember that the label property is defined in theItemabstract 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
DateFieldobject with the label as "Today's date" and the mode asDateField.DATE:DateField date = new DateField("Today's date", DateField.DATE);To display a date field, first create a
Formobject, and then use theappend( )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
DATEinput mode is selected, the MIDlet would display a <date> item for the user to select, as shown in Figure 5-14. Once selected, it will display the current calendar date, and you should be able to set a new date.
Figure 5-14. A date field representing the calendar date ![]()
If the
DateField.TIMEinput mode is used, the MIDlet would display a <time> item for the user to select, as shown in Figure 5-15. Once selected, the current clock time information will be displayed, and you can likewise set a new time.
Figure 5-15. A date field representing clock time information ![]()
Finally, if the
DateField.DATE_TIMEinput 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 5-16.
Figure 5-16. A date field represented with the DATE_TIME constant ![]()
The second
DateFieldconstructor is used to create a date field specifying its label, input mode, and time zone information. For example, the following snippet of code creates aDateFieldobject where the time zone is GMT:DateField date = new DateField("date", DateField.DATE,TimeZone.getTimeZone("GMT"));If the
TimeZonefield isnull, 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
TimeZoneclass is part of thejava.utilpackage, which has been inherited from theJ2SE.Gauge
A
Gaugeobject represents a bar graph display that can be used within a form. TheGaugeclass has the following constructor:public Gauge(String label, boolean interactive, int maxValue,int initialValue);This constructor is used to create a new
Gaugeobject 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
Gaugeobject 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
Gaugeobject is created, it can be placed on aFormcomponent, like the other components that we've seen:Form form = new Form("item");form.append(gauge);This interactive gauge is shown in Figure 5-17. 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.
Figure 5-17. 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 5-18. Note here that the non-interactive form of a gauge is level from right to left.
Figure 5-18. A non-interactive gauge representing a progress bar ![]()
Image and ImageItem
An
ImageItemobject is an image component that contains a reference to anImageobject. First, let's briefly introduce theImageclass. We will revisit it again later when we talk about low-level APIs.The
Imageclass 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, orImageItemmust be immutable, since the implementation will use them to update the display without notifying the application. Otherwise, the containingAlertorFormwould have to be updated on every graphics call.A mutable image can be created using one of the static
createImage( )methods of theImageclass.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
Formobject 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 5-19 depicts the screen shown with this example.
Figure 5-19. Placing an Image object on a form ![]()
The
Imageclass 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
Graphicsobject 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 theImageItemclass, which provides control and layout whenImageobjects are added to a form or an alert. To create an ImageItem object, use theImageItemconstructor:public ImageItem(String label, Image img, int layout,String altText);This constructor is used to create a new immutable
ImageItemobject with a given label, image, layout directive, and alternative text string. ThealtTextparameter 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 theImageItemclass:
ImageItem.LAYOUT_CENTERThe image should be horizontally centered.
ImageItem.LAYOUT_DEFAULTYou should use the default formatting of the container of the image.
ImageItem.LAYOUT_LEFTThe image should be close to the left edge of the drawing area.
ImageItem.LAYOUT_NEWLINE_AFTERA new line should be started after the image is drawn.
ImageItem.LAYOUT_NEWLINE_BEFOREA new line should be started before the image is drawn.
ImageItem.LAYOUT_RIGHTThe 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:
ImageItem.LAYOUT_DEFAULTcannot be combined with any other directive.
ImageItem.LAYOUT_LEFT,ImageItem.LAYOUT_RIGHT, andImageItem.LAYOUT_CENTERare mutually exclusive.
- You can combine
ImageItem.LAYOUT_LEFT,ImageItem.LAYOUT_RIGHT, and ImageItem.LAYOUT_CENTERwithImageItem.LAYOUT_NEWLINE_AFTERandImageItem.LAYOUT_NEWLINE_BEFORE.
TIP: The layout directives serve merely as a hint, but it may be ignored by the implementation. Such is the case withSun's MIDP reference implementation.The
ImageItemclass 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
ImageItemobject, use the aboveImageItemconstructor: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 5-19, except that this one would have a title for the
ImageItemobject.StringItem
A
StringItemobject is a text component item that may contain a string that cannot be edited by the user. AStringItemhas a label that can be modified by the application. The contents ofStringItemcan be modified by the application as well. Here is the constructor:public StringItem(String label, String contents);Creating a
StringItemobject is easy:StringItem si = new StringItem("label", "contents");The
setText()andgetText( )methods are used to set and get theStringItemcontents; thesetLabel()andgetLabel( )methods, which are defined in theItemabstract class, are used to set and get the label of theStringItem:public void setText(String s);public void setLabel(String l);public String getText( );public String getLabel( );The following snippet of code creates a
StringItemobject and places it within aFormobject. The form is then set to be the current screen, as shown in Figure 5-20.
Figure 5-20. 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);TextField
Unlike
StringItem, aTextFieldobject is an editable text component that may be placed on aForm. Similar to aTextBox, however, aTextFieldhas 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 usinggetMaxSize( ). But, as mentioned earlier, in Sun's MIDP reference implementation, thegetMaxSize( )method returns the size requested by the application.Use a
TextFieldobject if your MIDlet requires input from the user. ATextFieldobject can be created as an instance of the TextField class, which has the following constructor:public TextField(String label, String text, int maxSize, intconstraints);This constructor is used to create a new
TextFieldobject 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 theTextField's static constants, which are shared withTextBoxas discussed earlier, and they are:TextField.ANY,TextField.EMAILADDR,TextField.NUMBER,TextField.PASSWD,TextField.PHONENUMBER, andTextField.URL. Again, if you use a constraint other thanTextField.ANY, theTextFieldwill 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 thesetMaxSize( )method.public int getMaxSize( );public void setMaxSize(int size);You can set or retrieve the entire text in the
TextFieldwith thesetString( )andgetString( )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, orreplace the current text are identical toTextBox: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,TextFieldincludes 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 5-21.
Figure 5-21. 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);Creating Low-Level GUI Components
In the high-level API, you have no control of what is displayed on the screen and very little freedom to "play" with the components programmatically. The implementation is responsible for selecting the best approach for the device. Some applications, however, such as games, may need more control over what is drawn on the screen. The MIDP
javax.microedition.lcduipackage also provides a low-level API for handling such cases.In order to directly draw lines, text, and shapes on the screen, you must use the
Canvasclass. TheCanvasclass provides a blank screen on which a MIDlet can draw. For example, let's draw the string "HelloWorld" on the screen. There's a simple way to do this: subclass theCanvasclass, which is an abstract class that extendsDisplayable, and override thepaint( )method. The resulting class,MyCanvas, is shown in Example 5-1.The implementation of the
paint( )method uses the drawing capabilities of thejavax.microedition.lcdui.Graphicsclass. In thepaint( )method, the drawing color is set to red, then a rectangle is drawn in the current color. The methodsgetWidth( )andgetHeight( )return the width and height of theCanvas, respectively. The next call tosetColor( )sets the drawing color to white; then the string "Hello World!" is drawn in the top left corner of the screen.Example 5-1: Subclassing Canvas
import javax.microedition.lcdui.*; public class MyCanvas extends Canvas { public void paint(Graphics g) { g.setColor(255, 0, 0); g.fillRect(0, 0, getWidth(), getHeight( )); g.setColor(255, 255, 255); g.drawString("Hello World!", 0, 0, g.TOP | g.LEFT); } }Now, in order to view the
MyCanvas, it must be instantiated and displayed. SinceCanvasis a subclass ofDisplayable, it can be displayed the same way any other screen using thesetCurrent( )method. Example 5-2 shows the resulting MIDlet.Example 5-2: Instantiating and displaying MyCanvas
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class MyMidlet extends MIDlet { public MyMidlet( ) { // constructor } public void startApp( ) { Canvas canvas = new MyCanvas( ); Display display = Display.getDisplay(this); display.setCurrent(canvas); } public void pauseApp( ) { } public void destroyApp(boolean unconditional) { } }If you run this in the Wireless Toolkit emulator, you will see something similar to Figure 5-22. Note from Example 5-1 that the colors are set to red and white, but since a grayscale display is being used, the colors are mapped to appropriate shades of black and white. Try switching displays to see which devices give a better feel for the colors.
Figure 5-22. Drawing "Hello World!" on a Canvas ![]()
Drawing Graphics
The (0,0) coordinate represents the upper left corner of the display. The numeric value of the x-coordinate increases from left to right, and the numeric value of the y-coordinate increases from top to bottom. Applications should always check the dimensions of the drawing area by using the following methods of the
Canvasclass:public int getHeight( );public int getWidth( );These two methods return the height and width of the displayable area in pixels, respectively.
The drawing model used is called pixel replacement. It works by replacing the destination pixel value with the current pixel value specified in the graphics objects being used for rendering. A 24-bit color model is provided with 8 bits each for Red, Green, and Blue (RGB). However, since not all devices support color, colors requested by applications will be mapped into colors available on the devices. A well-written application, however, may check if a device supports color. This can be done using the
isColor()andnumColors( )methods of theDisplayclass, which we covered earlier in the chapter.The
Graphicsclass provides thesetColor()andgetColor( )methods for setting and getting the color. Unlike the AWT/Swing, however, there is nosetBackground( )andsetForeground(), so you need to explicitly callfillRect( ),as shown in Example 5-1. Most of the other methods in theGraphicsclass are self-explanatory and similar to methods in the AWT version of this class. However, let's go over a few of them here to see how they work in the J2ME environment.Double Buffering
The double buffering technique is often used to perform smooth effect animation. In this technique, you do not draw to the display, but instead to a copy of the display (an off-screen buffer) that is maintained in memory. When you are done drawing to the buffer, you then copy the contents of the buffer to the display. The rationale here is that copying the contents of memory to the display is faster than drawing by using primitives.
To implement double buffering, first create a mutable image with the size of the screen:
int width = getWidth( );int height = getHeight( );Image buffer = Image.createImage(width, height);Next, obtain a graphics context for the buffer:
Graphics gc = buffer.getGraphics( );Now, you can draw to the buffer:
// animate// ..gc.drawRect(20, 20, 25, 30);When you need to copy the buffer to the screen, you can override the
paint( )method to draw the buffer to the devicedisplay:public void paint(Graphics g) {g.drawImage(buffer, 0, 0, 0);}Note that some MIDP implementations are already double-buffered, and therefore this work may not be necessary. To check if the graphics are double-buffered by an implementation, use the
Canvas. isDoubleBuffered( )method.Threading Issues
The MIDP GUI APIs are thread-safe. In other words, the methods can be called at any time from any thread. The only exception is the
serviceRepaints( )method of theCanvasclass, which immediately calls thepaint( )method to force immediate repainting of the display. This means that ifpaint( )tries to synchronize on any object that is already locked by the application whenserviceRepaints( )is called, the application will deadlock. To avoid deadlocks, do not lock an object that will be used by thepaint()method ifserviceRepaints( )is involved.In addition, you can use the
callSerially( )method of theDisplayclass to execute code after all pending repaints are served, as shown in the following segment of code:class TestCanvas extends Canvas implements Runnable {void doSomething( ) {// code fragment 1callSerially(this);}public void run( ) {// code fragment 2}}Here, the object's
run( )method will be called after the initial call.Fonts
Fonts
cannot be created by applications. Instead, an application requests a font based on attributes (i.e., size, face, style) and the underlying implementation will attempt to return a font that closely resembles the requested font. TheFontclass represents various fonts and metrics. There are threefont attributes defined in theFontclass, and each may have different values, as follows:
- Face
MONOSPACE,PROPORTIONAL,SYSTEM
- Size
SMALL,MEDIUM,LARGE
- Style
BOLD,ITALIC,PLAIN,UNDERLINEDFor example, to specify a medium size font, use
Font.SIZE_MEDIUM, and to specify an italic style, useFont.STYLE_ITALIC, and so on. Values for the style attributes may be combined using the OR (|) operator; values for the other attributes may not be combined. For example, the value of this style attribute specifies a plain, underlined font:STYLE_PLAIN | STYLE_UNDERLINEDHowever, the following is illegal:
SIZE_SMALL | SIZE_MEDIUMThis is also illegal:
FACE_SYSTEM | FACE_MONOSPACEEach font in the system is actually implemented individually, so in order to obtain an object representing a font, use the
getFont( )method. This method takes three arguments for the font face, size, and style, respectively. For example, the following snippet of code obtains aFontobject with the specified face, style, and size attributes:Font font = Font.getFont(FACE_SYSTEM, STYLE_PLAIN, SIZE_MEDIUM);If a matching font does not exist, the implementation will attempt to provide the closest match, which is always a valid
Fontobject.Once a font is obtained, you can use methods from the
Fontclass to retrieve information about that font. For example, you can use the methodsgetFace(),getSize( ), andgetStyle( )to retrieve information about the face, size, and style of the font, respectively.Let's look at an example. The code in Example 5-3 subclasses the
Canvasclass. In this example, the drawing color is set to white, a rectangle is drawn in the current color, then the drawing color is set to black. The rest of the code draws the system fonts on the device screen, as shown in Figure 5-23.
Figure 5-23. Drawing system fonts on the device screen ![]()
Example 5-3: Using fonts
import javax.microedition.lcdui.*; public class FontCanvas extends Canvas { public void paint(Graphics g) { g.setColor(0xffffff); g.fillRect(0, 0, getWidth(), getHeight( )); g.setColor(0x000000); g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE)); g.drawString("System Font", 0, 0, g.LEFT | g.TOP); g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM)); g.drawString("Medium Size", 0, 15, g.LEFT | g.TOP); g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM)); g.drawString("Bold Style", 0, 30, g.LEFT | g.TOP); g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_ITALIC, Font.SIZE_MEDIUM)); g.drawString("Italic Style", 0, 45, g.LEFT | g.TOP); g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_UNDERLINED, Font.SIZE_MEDIUM)); g.drawString("Underlined Style", 0, 60, g.LEFT | g.TOP); } }import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class FontMidlet extends MIDlet { public FontMidlet( ) { // constructor } public void startApp( ) { Canvas canvas = new FontCanvas( ); Display display = Display.getDisplay(this); display.setCurrent(canvas); } public void pauseApp( ) { } public void destroyApp(boolean unconditional) { } }Guidelines for GUI Programming for MIDP Devices
As we close this chapter, keep in mind some important guidelines when designing MIDlets with graphical API functionality:
- Be sure to make the MIDlet user interface simple and easy to use. Remember that your applications will likely be used by novice users who probably haven't used a J2ME-enabled phone and may not be familiar with its interface.
- Use the high-level API as much as possible, so that your MIDlets are portable across different handheld devices.
- If your application requires you to use the low-level API, keep to the platform-independent part of the low-level API. This means that your MIDlets should not assume any other keys than those defined in the
Canvasclass. We'll discuss this in more detail in the next chapter.
- MIDlets should never assume any specific screen size; instead, they should query the size of the display and adjust accordingly.
- Entering alphanumeric data through a handheld device can be tedious. If possible, provide a list of choices from which the
user can select.
Back to: Learning Wireless Java
© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com