|
Tech Tips archive
June 22, 2001
WELCOME to the Java Developer Connection (JDC)
Java 2 Platform, Micro Edition
(J2ME) Tech Tips, for April 16, 2001.
This issue covers:
The J2ME Tech Tips are written by Eric Giguere (http://www.ericgiguere.com), an engineer at iAnywhere Solutions, inc. Eric is the author of the book "Java 2 Micro
Edition: Professional Developer's Guide" and co-author of the
upcoming "Mobile Information Device Profile for Java 2 Micro
Edition," both books in John Wiley & Sons' Professional
Developer's Guide series.
USING THE MIDP LIST COMPONENT
The Mobile Information Device Profile (MIDP) groups its user
interface components into two sets of classes: the high-level
API and the low-level API. With the high-level API you define
your user interface using a set of platform-independent
abstractions and let the MIDP implementation decide the look
and behavior of the user interface. The low-level API gives you
complete control (and responsibility) of the drawing area and the
processing of the raw input events. The low-level API was covered
in the J2ME Tech Tip for March 19, 2001 "Using the MIDP Low-Level
User Interface API".
This Tech Tip examines the List component, part of the
high-level API. All MIDP user interface components are defined
in the javax.microedition.lcdui package.
The List component displays a set of selectable strings. An
optional image can also be displayed along with each string.
The implementation displays the strings in some kind of list --
the exact format of the display is undefined -- and provides
a way for the user to navigate from one item in the list to
another, selecting or deselecting items as appropriate. The
navigation and selection procedures are separate. In other words,
the user can navigate to a specific item without selecting or
deselecting it. This is referred to as moving the input focus.
The List class extends Screen, which is the base class for all top-level windows in the high-level API. Only one screen is
ever visible at a time. A screen has an optional title.
Because the Screen class extends Displayable, Command objects can also be associated with List components. The List class also implements the Choice interface, which defines a number of methods that the List component has in common with another component of the high-level API: the ChoiceGroup component.
A List component supports three modes of item selection. The
first mode, List.EXCLUSIVE, lets the user select exactly one item
from the list. If the user selects an item and another item is
already selected, the previous item is automatically deselected.
Conceptually, it's as if the list was composed of a set of radio buttons, and implementations may in fact display it that way. The
second mode, List.MULTIPLE, lets the user select zero or more of
the items simultaneously. It's as if the list was composed of a
set of checkboxes. The final mode, List.IMPLICIT, is like the
exclusive mode, but the act of selecting an item also triggers an
event, as if the user had triggered a command (more on this
below).
The List class defines two constructors. Both constructors take
the screen title and the list mode (one of List.EXCLUSIVE,
List.MULTIPLE, or List.IMPLICIT). The second constructor also takes an array of strings and an array of images in order to
initialize the List. However, the initialization can be done
separately. For example, here's one way to construct a list
of items:
List l = new List( "Choose fruit:", List.EXCLUSIVE );
l.append( "orange", null );
l.append( "apple", null );
l.append( "pear", null );
The alternative is to use the array form of the constructor:
String[] fruitNames = { "orange", "apple", "pear" };
List l = new List( "Choose fruit:", List.EXCLUSIVE,
fruitNames, null );
Note that images are entirely optional. Even if you specify them,
the implementation might ignore them. So it's safe to pass in
null whenever an image or array of images is requested.
Before displaying a List component, you'll want to register
a command listener for it:
List l = ....;
CommandListener listener = ....; // often "this"
l.setCommandListener( listener );
A command listener is an instance of any class that implements
the CommandListener interface. Often the MIDlet's main class is
the listener. Only one listener can be registered at a time.
A List in EXCLUSIVE or MULTIPLE mode must also register at least one Command object, otherwise no events will be sent to the
command listener. This is because the EXCLUSIVE and MULTIPLE modes do not trigger any events as the user interacts with the list.
It's usually a good idea to add commands to lists in IMPLICIT
mode as well as in EXCLUSIVE or MULTIPLE mode. When the user selects an item from an IMPLICIT mode list, the list notifies its command listener using the special Command object defined as
List.SELECT_COMMAND. This object gets passed to the listener's
commandAction method as the first argument whenever a new item is
selected. In other words, you check for implicit selection using
code like this:
public void commandAction( Command c, Displayable d ){
if( c == List.SELECT_COMMAND ){
// implicit selection...
} else if( ..... ){
..... // etc. etc.
}
}
|
Make sure that any operation performed in response to
SELECT_COMMAND is intuitively obvious to the user. For example,
a List component that displays a list of emails might respond to
SELECT_COMMAND by displaying the text of the selected email
message. Other mail management operations are accessed by
registering appropriate Command objects.
The List contents, that is, the text and images displayed by the
List, can be changed at any time. List defines append, delete, insert, and set methods for this purpose. A common requirement, for example, is to delete the contents of a list. You can do this easily, like this:
public static void deleteListContents( List l ){
int n = l.size();
while( n-- > 0 ){
l.delete( n );
}
}
|
The size method returns the number of items currently stored in
the List.
If you find yourself doing these kinds of operations repeatedly,
you might want to extend List to augment it with your own
features, as in the following:
public class ExtendedList extends List {
public ExtendedList( String title, int mode ){
super( title, mode );
}
public ExtendedList( String title, int mode,
String[] itemText, Image[]
itemImages ){
super( title, mode, itemText, itemImages );
}
public void deleteAll(){
int n = size();
while( n-- > 0 ){
delete( n );
}
}
}
|
After a List has been constructed, you can obtain the index of the
selected item at any time. In EXCLUSIVE or IMPLICIT mode, use getSelectedIndex, which returns the index (starting at 0) of the selected item:
List l = ....; // some list
int which = l.getSelectedIndex();
Lists in MULTIPLE mode return -1 for getSelectedIndex, because more than one item can be selected at any given time. Use
getSelectedFlags to return the selected state of each item into an
array you supply:
List l = ....; // some list
boolean[] selected = new boolean[ l.size() ];
l.getSelectedFlags( selected );
for( int i = 0; i < selected.length; ++i ){
if( selected[i] ){
system.out.println( "Item " + i + " is
selected!" );
}
}
|
You can also check the selected state of an individual item at
any time by calling isSelected. You can set its state by calling
setSelectedFlags or setSelectedIndex. For example, here's how to toggle the selected items in a MULTIPLE mode List:
public void toggleItems( List l ){
boolean[] selected = new boolean[ l.size() ];
l.getSelectedFlags( selected );
for( int i = 0; i < selected.length; ++i ){
selected[i] = !selected[i];
}
l.setselectedflags( selected );
}
|
Another way to toggle the selected items is to set each item's
selected state individually:
public void toggleItems( List l ){
int n = l.size();
for( int i = 0; i < n; ++i ){
l.setselectedindex( i, !l.isselected( i ) );
}
}
|
The latter method might cause excessive repainting of the list,
however, and should be avoided in favor of calling setSelectedFlags.
Each item in a List can have an associated image. An image is an
instance of the Image class, usually obtained by calling
Image.createImage, and passing it the path of an image in the
MIDlet suite's JAR file. For example:
Image checked = null;
Image unchecked = null;
try {
checked = Image.createImage( "/images/check.png" );
unchecked = Image.createImage(
"/images/unchecked.png" );
}
catch( java.io.IOException e ){
}
|
You can also create images dynamically by using the Image class's
offscreen buffer capability. However, any image used in a List or
other high-level UI component must be an immutable, that is, it
must be an unchangeable image. (See the Image class documentation
for information on how to do this with dynamically-generated
images.)
Once you have an image or set of images, you can assign them to
the items either in the constructor or as arguments to the append,
insert or set methods. You assign the items in the constructor
by passing in an array of images equal in length to the array of
strings that define the items. Here's an example that illustrates
assigning images to the append method:
List l = ....; // some list
try {
l.append( "orange", Image.createImage(
"/orange.png" ) );
l.append( "apple", Image.createImage(
"/apple.png" ) );
l.append( "pear", Image.createImage(
"/pear.png" ) );
}
catch( IOException e ){
}
|
Keep the images as small as possible, no more than 10-to-16
pixels high. Make them all the same size to ensure that the text
is painted correctly. Don't depend on the images being there,
however, and make sure the item text is descriptive enough without
the image.
Let's end the tip with a simple MIDlet that demonstrates the use
of the List component.
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class ListDemo extends MIDlet {
private Display display;
private int mode = List.IMPLICIT;
private Command exitCommand = new Command( "Exit",
Command.SCREEN, 2 );
private Command selectCommand = new Command( "Select",
Command.OK, 1 );
private Command nextCommand = new Command( "Next",
Command.SCREEN, 2 );
public ListDemo(){
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
protected void pauseApp(){
}
protected void startApp() throws
MIDletStateChangeException {
if( display == null ){ // first time called...
initMIDlet();
}
}
private void initMIDlet(){
display = Display.getDisplay( this );
display.setCurrent( new SampleList( mode ) );
}
public void exitMIDlet(){
notifyDestroyed();
}
public static final String[] items = {
"First", "Second", "Third", "Fourth"
};
class SampleList extends List implements
CommandListener {
private int mode;
SampleList( int mode ){
super( "", mode, items, null );
addCommand( exitCommand );
addCommand( selectCommand );
addCommand( nextCommand );
setCommandListener( this );
switch( mode ){
case IMPLICIT:
setTitle( "Implicit" );
break;
case EXCLUSIVE:
setTitle( "Exclusive" );
break;
case MULTIPLE:
setTitle( "Multiple" );
break;
}
this.mode = mode;
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
} else if( c == selectCommand ){
showSelection( false );
} else if( c == SELECT_COMMAND ){
showSelection( true );
} else if( c == nextCommand ){
if( mode == List.IMPLICIT ){
mode = List.EXCLUSIVE;
} else if( mode == List.EXCLUSIVE ){
mode = List.MULTIPLE;
} else {
mode = List.IMPLICIT;
}
display.setCurrent( new SampleList(
mode ) );
}
}
private void showSelection( boolean implicit ){
Alert alert = new Alert(
implicit ? "Implicit Selection"
: "Explicit Selection" );
StringBuffer buf = new StringBuffer();
if( mode == MULTIPLE ){
boolean[] selected = new boolean[ size() ];
getSelectedFlags( selected );
for( int i = 0; i < selected.length; ++i ){
if( selected[i] ){
if( buf.length() == 0 ){
buf.append(
"You selected: " );
} else {
buf.append( ", " );
}
buf.append( getstring( i ) );
}
}
if( buf.length() == 0 ){
buf.append( "No items are
selected." );
}
} else {
buf.append( "You selected " );
buf.append( getstring(
getselectedindex() ) );
}
alert.setstring( buf.tostring() );
alert.settimeout( alert.forever );
display.setcurrent( alert,
display.getcurrent() );
}
}
}
|
ENUMERATING, FILTERING, AND SORTING MIDP RECORD STORES
The Record Management System (RMS), part of the Mobile
Information Device Profile (MIDP), lets you store arbitrary byte
arrays as records in a database. The set of records is referred
to as a record store. The RMS assigns a record ID to each record
when it is created. The record ID is an integer greater than or
equal to 1. The application uses this ID to get and set the
content of a record.
Record IDs are unique within a record store. In other words,
after a record ID has been assigned to a record, the record ID
is not reused, even if that record is deleted. This makes it easy
to track individual records. It does, however, pose a problem:
how do you get a list of all the records in a record store, given
that they aren't necessarily in a continuous, sequential order?
The answer is to use an enumeration.
The RecordStore class defines an enumerateRecords method that returns a RecordEnumeration. RecordEnumeration is an interface
whose purpose is similar to the java.util.Enumeration interface,
but with more capabilities. (The RecordEnumeration interface,
like all RMS classes and interfaces, is defined in the
javax.microedition.rms package). Here is the definition for
RecordEnumaration:
public interface RecordEnumeration {
void destroy();
boolean hasNextElement();
boolean hasPreviousElement();
boolean isKeptUpdated();
void keepUpdated( boolean keepUpdated );
byte[] nextRecord() throws InvalidRecordIDException,
RecordStoreNotOpenException,
RecordStoreException;
int nextRecordId() throws InvalidRecordIDException;
int numRecords();
byte[] previousRecord() throws InvalidRecordIDException,
RecordStoreNotOpenException,
RecordStoreException;
int previousRecordId() throws InvalidRecordIDException;
void rebuild();
void reset();
}
|
RecordEnumeration lets you traverse through a set of records.
Unlike Enumeration, however, RecordEnumeration allows for bidirectional traversal of that set -- you can go backwards through the set of records as well as forwards. The set of records to traverse is defined by the enumerateRecords method.
To iterate over the entire set of records in a record store,
do the following:
RecordStore rs = .....; // an open record store
RecordEnumeration enum = null;
try {
enum = rs.enumerateRecords( null, null, false );
while( enum.hasMoreElements() ){
int id = enum.getNextRecordId();
// do something here with the record
}
}
catch( RecordStoreException e ){
}
finally {
enum.destroy();
}
|
The first two arguments to the enumerateRecords method are
used to filter and sort the records in an enumeration. (This tip
will discuss filtering and sorting shortly.) The last argument
determines whether the enumeration tracks changes to the record
store. If the last argument is true, the enumeration updates
itself as records are added to or deleted from a record store.
This can be an expensive operation, however, and for most
applications tracking is not required. Note that enumerateRecords
throws RecordStoreNotOpenException if the record store is not
open. RecordStoreNotOpenException is a subclass of
RecordStoreException.
RecordEnumeration defines two methods to traverse forward through
the enumeration: getNextRecordId and getNextRecord. It also defines two methods to traverse backwards: getPreviousRecordId
and getPreviousRecord. Each method moves to the next or previous
record in the enumeration, returning either the ID of the record
(getNextRecordId and getPreviousRecordId) or its contents (getNextRecord and getPreviousRecord). An application calls hasNextElement or hasPreviousElement to determine if there are any more records to traverse in a specific direction.
You can reset the enumeration at any time by calling reset.
When an application is done with an enumeration it must call the
enumeration's destroy method. This frees up any resources used by
the enumeration.
If the first two arguments to enumerateRecords are null, all the
records in the record store are returned in an undefined order. To
return a subset of the records or to return the records in a
specific order, you must define a filter, a comparator, or both.
To do this, pass in objects that implement the RecordFilter or
RecordComparator interfaces, depending on whether you defined
a filter, comparator, or both.
The RecordFilter interface defines a single method:
public interface RecordFilter {
boolean matches( byte[] recordData );
}
A filter is an instance of a class that implements the
RecordFilter interface. If a filter is defined in the call to
enumerateRecords, the filter's matches method is called for each
record in the record store. The matches method determines if the
record is included in the enumeration. Here, for example, is a
filter that filters out empty records or records whose first byte
is set to zero:
public class MyFilter implements RecordFilter {
public boolean matches( byte[] recordData ){
return( recordData.length > 0 && recordData[0] != 0 );
}
}
|
Use the filter like this:
enum = rs.enumerateRecords( new MyFilter(), null, false );
Note that the filter is passed the contents of a record,
but not the record ID or a reference to the record store itself.
The RecordComparator interface also defines a single method:
public interface RecordComparator {
boolean compare( byte[] rec1, byte[] rec2 );
int EQUIVALENT = 0;
int FOLLOWS = 1;
int PRECEDES = -1;
}
|
A comparator is an instance of a class that implements the
RecordComparator interface. If a comparator is defined in the
call to enumerateRecords, the enumerator sorts the records in the
set. The enumerator calls the comparator's compare method to
determine the relative order of two records. The comparator
returns EQUIVALENT if both records are equivalent, FOLLOWS if the
first record follows the second record, or PREVIOUS is the first
precedes the second record. Here is a comparator that sorts
records based on their length:
public class MyComparator implements RecordComparator {
public boolean compare( byte[] rec1, byte[] rec2 ){
if( rec1.length == rec2.length ){
return EQUIVALENT;
} else if( rec1.length < rec2.length ){
return precedes;
} else {
return follows;
}
}
}
|
Of course, most comparators would compare records based on their
contents. Use the comparator like this:
enum = rs.enumerateRecords( null, new MyComparator(), false );
Again, only the contents of the records to compare are passed to
the comparator.
Both a filter and a comparator can be associated with an
enumeration. The filter is called first to determine which
records are in the enumeration. The comparator is then called to
sort those records.
If tracking is enabled, filtering and sorting occurs whenever the
record store is modified. This can be quite expensive to perform.
You can enable or disable an enumeration's tracking of the
underlying record store by using the keepUpdated method.
If tracking is disabled but you want to "refresh" the enumeration
from the current set of records in the record store, call
the rebuild method.
Let's end this tip with a simple MIDlet that demonstrates how to
fill a List component from a record store. The records in the
record store contain the first and last names of a group of
people. The MIDlet includes a screen that lets you choose how to
sort and filter the records.
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;
// Demonstrates simple record sorting and filtering
public class EnumDemo extends MIDlet
implements CommandListener {
// Data members we need
private Display display;
private RecordStore rs;
private EnumList enumListScreen;
private SortOptions sortOptionsScreen;
private String firstName;
private String lastName;
private byte[] data = new byte[200];
private ByteArrayInputStream bin =
new ByteArrayInputStream( data );
private DataInputStream din =
new DataInputStream( bin );
// Define the four commands we use
private Command exitCommand = new Command( "Exit",
Command.EXIT, 1 );
private Command sortCommand = new Command( "Sort",
Command.SCREEN, 1 );
private Command cancelCommand = new Command( "Cancel",
Command.CANCEL, 1 );
private Command okCommand = new Command( "OK",
Command.OK, 1 );
// Define the sorting modes
private static final int SORT_NONE = 0;
private static final int SORT_FIRST_LAST = 1;
private static final int SORT_LAST_FIRST = 2;
// Define the filtering modes
private static final int FILTER_NONE = 0;
private static final int FILTER_STARTSWITH = 1;
private static final int FILTER_CONTAINS = 2;
// A simple class to hold the parts of a record
private static class Record {
String firstName;
String lastName;
}
// Precanned names
private static final String[][] names = {
{ "Eric", "Giguere" },
{ "John", "Doe" },
{ "Lisa", "Munro" },
{ "Stephanie", "Kwaly" },
{ "Dave", "Boyer" },
{ "Gwen", "Stephens" },
{ "Jennifer", "Lopert" },
{ "Ed", "Ort" },
};
// Constructor
public EnumDemo(){
}
// Clean up
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
// Close the record store for now
protected void pauseApp(){
closeRecordStore();
}
// Initialize things and reopen record store
// if not open
protected void startApp() throws
MIDletStateChangeException {
if( display == null ){ // first time called...
initMIDlet();
}
if( rs == null ){
openRecordStore();
}
}
// Once-only initialization code
private void initMIDlet(){
display = Display.getDisplay( this );
enumListScreen = new EnumList();
sortOptionsScreen = new SortOptions();
if( openRecordStore() ){
enumListScreen.resort();
display.setCurrent( enumListScreen );
}
}
// Termination code
public void exitMIDlet(){
closeRecordStore();
notifyDestroyed();
}
// Add a first-last name pair to the record store
private void addName( String first, String last,
ByteArrayOutputStream bout,
DataOutputStream dout ){
try {
dout.writeUTF( first );
dout.writeUTF( last );
dout.flush();
byte[] data = bout.toByteArray();
rs.addRecord( data, 0, data.length );
bout.reset();
}
catch( Exception e ){
}
}
// Fill record store with some precanned names
private void fillRecordStore(){
ByteArrayOutputStream bout =
new ByteArrayOutputStream();
DataOutputStream dout =
new DataOutputStream( bout );
for( int i = 0; i < names.length; ++i ){
addname( names[i][0], names[i][1], bout,
dout );
}
}
// open record store, if empty then fill it
private boolean openrecordstore(){
try {
if( rs != null ) closerecordstore();
rs = recordstore.openrecordstore(
"EnumDemo", true );
if( rs.getnumrecords() == 0 ){
fillrecordstore();
}
return true;
}
catch( recordstoreexception e ){
return false;
}
}
// close record store
private void closerecordstore(){
if( rs != null ){
try {
rs.closerecordstore();
}
catch( recordstoreexception e ){
}
rs = null;
}
}
// move to and read in a record
private boolean readrecord( int id, record r ){
boolean ok = false;
r.firstname = null;
r.lastname = null;
if( rs != null ){
try {
rs.getrecord( id, data, 0 );
r.firstname = din.readutf();
r.lastname = din.readutf();
din.reset();
ok = true;
}
catch( exception e ){
}
}
return ok;
}
// event handling
public void commandaction( command c, displayable d ){
if( c == exitcommand ){
exitmidlet();
} else if( c == sortcommand ){
display.setcurrent( sortoptionsscreen );
} else if( d == sortoptionsscreen ){
if( c == okcommand ){
enumlistscreen.resort();
}
display.setcurrent( enumlistscreen );
}
}
// main screen -- a list of names
class enumlist extends list
implements recordcomparator,
recordfilter {
private int sortby;
private int filterby;
private string filtertext;
private record r1 = new record();
private record r2 = new record();
// constructor
enumlist(){
super( "Enum Demo", implicit );
addcommand( exitcommand );
addcommand( sortcommand );
setcommandlistener( enumdemo.this );
}
// resort the data and refill the list
public void resort(){
sortby = sortoptionsscreen.getsorttype();
filterby = sortoptionsscreen.getfiltertype();
filtertext = sortoptionsscreen.getfiltertext();
recordcomparator comparator = null;
recordfilter filter = null;
if( sortby != 0 ){
comparator = this;
}
if( filterby != 0 ){
filter = this;
}
deleteall();
try {
recordenumeration enum = rs.enumeraterecords(
filter, comparator, false );
record r = new record();
while( enum.hasnextelement() ){
int id = enum.nextrecordid();
if( readrecord( id, r ) ){
if( sortby == sort_last_first ){
append( r.lastname + ", " +
r.firstname, null );
} else {
append( r.firstname + " " +
r.lastname, null );
}
}
}
enum.destroy();
}
catch( recordstoreexception e ){
}
}
// delete all items in the list
private void deleteall(){
int n = size();
while( n > 0 ){
delete( --n );
}
}
// The comparator
public int compare( byte[] rec1, byte[] rec2 ){
try {
ByteArrayInputStream bin =
new ByteArrayInputStream( rec1 );
DataInputStream din =
new DataInputStream( bin );
r1.firstName = din.readUTF();
r1.lastName = din.readUTF();
bin = new ByteArrayInputStream( rec2 );
din = new DataInputStream( bin );
r2.firstName = din.readUTF();
r2.lastName = din.readUTF();
if( sortBy == SORT_FIRST_LAST ){
int cmp = r1.firstName.compareTo(
r2.firstName );
System.out.println( r1.firstName +
" compares to " + r2.firstName +
" gives " + cmp );
if( cmp != 0 ) return (
cmp < 0 ? precedes : follows );
cmp = r2.lastname.compareto( r2.lastname );
if( cmp != 0 ) return (
cmp < 0 ? precedes : follows );
} else if( sortby == sort_last_first ){
int cmp = r1.lastname.compareto(
r2.lastname );
if( cmp != 0 ) return (
cmp < 0 ? precedes : follows );
cmp = r2.firstname.compareto(
r2.firstname );
if( cmp != 0 ) return (
cmp < 0 ? precedes :
follows );
}
}
catch( exception e ){
}
return equivalent;
}
// the filter
public boolean matches( byte[] rec ){
try {
bytearrayinputstream bin =
new bytearrayinputstream( rec );
datainputstream din =
new datainputstream( bin );
r1.firstname = din.readutf();
r1.lastname = din.readutf();
if( filterby == filter_startswith ){
return( r1.firstname.startswith(
filtertext )
||
r1.lastname.startswith(
filtertext ) );
} else if( filterby ==
filter_contains ){
return( r1.firstname.indexof(
filtertext )
>= 0 ||
r1.lastName.indexOf(
filterText ) >= 0 );
}
}
catch( Exception e ){
}
return false;
}
}
// The options screen for choosing which sort and
// filter modes to use, including the filter text
class SortOptions extends Form {
// Constructor
SortOptions(){
super( "Sort Options" );
addCommand( okCommand );
addCommand( cancelCommand );
setCommandListener( EnumDemo.this );
append( sortTypes );
append( filterTypes );
append( filterText );
}
// Return current sort type
public int getSortType(){
return sortTypes.getSelectedIndex();
}
// Return current filter type
public int getFilterType(){
return filterTypes.getSelectedIndex();
}
// Return current filter text
public String getFilterText(){
return filterText.getString();
}
// Labels and user interface components
private String[] sortLabels =
{ "None", "First Last",
"Last, First" };
private String[] filterLabels =
{ "None", "Starts With",
"Contains" };
private ChoiceGroup sortTypes =
new ChoiceGroup(
"Sort Type:",
ChoiceGroup.EXCLUSIVE,
sortLabels, null );
private ChoiceGroup filterTypes =
new ChoiceGroup(
"Filter Type:",
ChoiceGroup.EXCLUSIVE,
filterLabels, null );
private TextField filterText = new TextField(
"Filter Text:",
null, 20, 0 );
}
}
|
Note
Sun respects your online time and privacy. The Java Developer
Connection mailing lists are used for internal Sun MicrosystemsTM purposes only. You have received this email because you elected to subscribe. To unsubscribe, go to the Subscriptions page, uncheck the appropriate checkbox, and click the Update button.
As of May 22, 2001, Sun Microsystems updated its Privacy Policy to give you a better understanding of Sun's Privacy Policy and Practice. If you have any questions, contact privacy@sun.com.
Subscribe
To subscribe to a JDC newsletter mailing list, go to the Subscriptions page, choose the newsletters you want to subscribe to, and click Update.
Feedback
Comments? Send your feedback on the J2ME Tech Tips to:
jdc-webmaster@sun.com
Archives
You'll find the J2ME Tech Tips archives at:
http://java.sun.com/jdc/J2METechTips/index.html
Copyright
Copyright 2001 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.
This Document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html
- LINKS TO NON-SUN SITES
The J2ME Tech Tips may provide, or third parties may provide, links to other Internet sites or resources. Because Sun has no control over such sites and resources, You acknowledge and agree that Sun is not responsible for the availability of such external sites or resources, and does not endorse and is not responsible or liable for any Content, advertising, products, or other materials on or available from such sites or resources. Sun will not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such Content, goods or services available on or through any such site or resource.
J2ME Tech Tips
June 22, 2001
Sun, Sun Microsystems, Java, Java Developer Connection, and J2ME and are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
|