MIDP 將它的用戶界面組件分為兩組類:高層 API 和底層 API。使用高層 API 你可以使用一組平台獨立的抽象類定義你的用戶界面,並讓 MIDP 實現確定用戶界面的外觀和操作。底層 API 是你獲得完全的畫圖區域控制並處理原始輸入事件。底層 API 在使用底層用戶界面 API 中介紹。
本文討論列表組件,高層 API 的一個組成部分。所有 MIDP 用戶界面組件在 Javax.microedition.lcdui 包中定義。
列表組件顯示一組可選擇的字符串。一組可選圖案也可以和每個字符串替換使用。實現顯示了在一些列表中的字符串—顯示的准確格式並沒有定義—並提供了一個途徑,是用戶能夠從列表中的一個項目轉換到另一個項目,根據需要選擇或不選擇某個項目。浏覽和選擇的處理流程是相互獨立的。換句話說,用戶可以浏覽一個特定的項目,但是並不確定選擇與不選擇。這是指移動輸入指針。
List類是Screen類的擴展,Screen類是高層 API 中所有頂層窗口的基本類。在同一時間段內,只有一個Screen是可見的。一個Screen有一個可選的標題。由於Screen類是Displayable類的擴展,命令對象也可以與List組件相關聯。List類也實現Choice界面,它定義了一些方法,這些方法是List組件與高層API的其它組件所共有的:ChoiceGroup組件。
List組件支持三種類型的項目選擇。第一種是List.EXCLUSIVE,是用戶准確的從列表中選擇一個項目。如果用戶在選擇一個項目時,另一個項目已經被選擇了,先前的一個項目將被自動取消選擇。從概念上看,列表就像一組Radio Buttons,實現實際上就是用這種方式顯示的。第二種是List.MULTIPLE,是用戶同時選擇零個或多個項目。就好像列表是由一組Checkbox組成的。最後一種是List.IMPLICIT,象是一種排它方式,但是選擇一個項目的動作同時也激發一個事件,就像用戶激活了一個命令(下面詳細介紹)。
List類定義兩個構造器。兩個構造器都使用屏幕的名稱和一個列表方式(List.EXCLUSIVE,List.MULTIPLE,List.IMPLICIT之中的一個)。第二個構造器也帶有一個字符串數組和一個圖像數組,用以初始化List。盡管如此,初始化可以分別進行。例如,這是構造項目列表的一種方式:
List l = new List( "Choose fruit:", List.EXCLUSIVE );
l.append( "orange", null );
l.append( "apple", null );
l.append( "pear", null );
另一種方式是使用數組形式的構造器:
String[] fruitNames = { "orange", "apple", "pear" };
List l = new List( "Choose fruit:", List.EXCLUSIVE,
fruitNames, null );
注意:圖像完全是可選項。即使你指定圖像,實現也可能忽略它們。這樣,無論什麼時候一個圖像或一組圖像被請求時,傳遞Null比較安全。
在顯示一個List組件之前,你會希望為它注冊一個命令監聽器:
List l = ....;
CommandListener listener = ....; // often "this"
l.setCommandListener( listener );
命令監聽器是任何一個實現CommandListener接口的類的實例。通常MIDlet的Main類是一個監聽器。同時只有一個監聽器可以被注冊。一個采用EXCLUSIVE或MULTIPLE方式的列表必須至少注冊一個Command對象,否則沒有事件會被發送到命令監聽器。這是因為在用戶操作列表時EXCLUSIVE和MULTIPLE方式不會激發任何事件。
一般情況下,為采用IMPLICIT方式的列表,象采用EXCLUSIVE和MULTIPLE方式的列表一樣,添加命令是一種好主意。在用戶從一個IMPLICIT列表種選擇項目時,列表使用定義為List.SELECT_COMMAND的特殊命令對象通知它的命令監聽器。這個對象在新的項目被選擇的時候被作為第一個參數傳遞到commandAction方法。換句話說,你可以使用如下代碼檢查implicit選擇:
public void commandAction( Command c, Displayable d ){
if( c == List.SELECT_COMMAND ){
// implicit selection...
} else if( ..... ){
..... // etc. etc.
}
}
請確認任何一個響應SELECT_COMMAND的操作對於用戶來說是直觀的。例如,顯示一個電子郵件的列表的List組件可以通過顯示選定的電子郵件信息的文本來響應SELECT_COMMAND。其它郵件管理操作是通過相應的注冊的命令對象來訪問的。
列表的內容,就是列表顯示的文本和圖像,可以在任何時候修改。列表為此定義了append,delete,insert和set方法。一個常見的需求,例如,刪除列表的一個內容。你可以這樣容易的實現:
public static void deleteListContents( List l ){
int n = l.size();
while( n-- > 0 ){
l.delete( n );
}
}
size方法返回目前在列表中存儲的項目的數量。
如果你發現你重復的進行這種操作,你可能希望為你的特性為列表增加參數,就像這樣:
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 );
}
}
}
在一個列表被構造後,你可以在任何時候獲得選擇的項目的索引。在EXCLUSIVE或IMPLICIT方式,使用getSelectedIndex,它返回選擇的項目的索引(從0開始):
List l = ....; // some list
int which = l.getSelectedIndex();
使用MULTIPLE方式的列表的getSelectedIndex返回-1。因為在任何的指定時間可以返回多於一個的項目。使用getSelectedFlags將每個選擇的項目的狀態返回到你指定的數組種:
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!" );
}
}
你也可以隨時檢查每一個選定的項目的狀態,是通過調用isSelected來實現。你可以通過調用setSelectedFlags或setSelectedIndex來設置它的狀態。例如,如何在MULTIPLE方式列表種所定選擇的項目:
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 );
}
另一個鎖定選擇的項目的方法是分別設置每一個項目為選擇狀態:
public void toggleItems( List l ){
int n = l.size();
for( int i = 0; i < n; ++i ){
l.setselectedindex( i, !l.isselected( i ) );
}
}
後一種方法將導致列表的刷新,無論怎樣,它可以避免調用setSelectedFlags。
列表中的每一個項目可以有一個關聯的圖像。一個圖像是Image類的一個實例,通常通過Image.createImage得到,並在將圖像在MIDlet包的JAR文件中的路徑傳遞給它。例如:
Image checked = null;
Image unchecked = null;
try {
checked = Image.createImage( "/images/check.png" );
unchecked = Image.createImage(
"/images/unchecked.png" );
}
catch( Java.io.IOException e ){
}
你也可以通過使用Image類的offscreen緩存器功能來動態創建圖像。無論怎樣,列表或其它高層用戶界面組件中使用的圖像必須是不可變的,就是說,它是一個不能修改的圖像。更多關於如何動態生成圖像的信息,參見Image類文檔。
一旦你有了一個或多個圖像,你可以通過構造器或作為參數傳遞個append,insert或set方法,來把它分配給列表的項目。你在構造器中分配圖像是傳遞一個與定義的項目數組同等長度的圖像數去給構造器。這裡是一個通過append方法分配圖像的例子:
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 ){
}
盡量使用小的圖像,不要超過10-16 pixels。采用同樣大小的圖像,以確保文本頁面的正確。而且不要依賴於圖像,確認項目的文本即使在沒有圖像的情況下,同樣是容易理解的。
讓我們以一個簡單的使用List組件的例子來結束這個tip。
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() );
}
}
}