除了基于屏幕的组件外,你还应该掌握使用表单把多个组件组织到一个屏幕上去。这一部分将讨论Form类和可以放置到表单上去的组件。
1. Form
一个表单对象是一个screen,它可以包含任意的项,包括只读的和可编辑的文本框,图像,日期域,gauge以及选项组组件。前面已提到,任何Item类的子类都可以放置到表单对象上去。Form类的构造器如下:
public Form(String title); public Form(String title, Item[] items); |
第一个构造器创建一个空的表单,仅有一个标题。第二个构造器创建一个含有标题和初始内容的表单。如,下面的程序创建一个空的表单,其标题是"Choose an Item",见图1。这是一个常规的屏幕。
图 1.一个空的form
|
Form form = new Form("Choose an Item"); |
Form对象并不使用任何布局管理器。代之的是,Form对象将象一个列表一样安排它的组件,通常是从顶到底。就象一个列表中的选项,表单中的各个项可以进行编辑,如插入,添加和删除。Form类的方法列举如下。
把一个图像加到表单的结尾,可以用:
public int append(Image img); |
下面方法添加一个Item 的子类化对象到表单的结尾:
public int append(Item item); |
下面方法添加一个字符串到表单的结尾:
public int append(String str); |
下面方法删除表单上在给定位置的项,同时改变表单的大小:
public void delete(int itemNum); |
你可以使用下面方法存取表单上的任何项,而表单内容保持不变。
public Item get(int itemNum); |
下面方法在表单上插入一项,插在指定索引的前面:
public void insert(int itemNum, Item item); |
下面方法替换表单上的前一项:
public int set(int itemNum, Item item); |
最后,你可用下面size( )方法来查找表单上的项的当前序号:
可以放置到一个表单上去的GUI组件有:ChoiceGroup,DateField,Gauge,ImageItem,StringItem和TextField。所有这些都是抽象类Item 的子类。稍后,我们将看到如何把这些项放置到屏幕上去。首先让我们依次作一下介绍。
2. Item
Item抽象类用作可以放置到表单或者alert上的组件的基类。所有的Item对象都有一个标签(如有一个字符串依附到其上),这可以用下面方法存取:
public String getLabel( ); public void setLabel(String s); |
该抽象类仅有这两个方法。
3. ChoiceGroup
ChoiceGroup对象描述了一组放置在表单上的可选择的选项。类似于List类,它也实现了Choice接口,而且还继承了Item抽象类。该对象可以指明选择一项,或者进行多个选择。ChoiceGroup类构造器如下:
public ChoiceGroup(String label, int choiceType); public ChoiceGroup(String label, int choiceType,String[] stringElements, Image[] imageElements); |
第一个构造器创建一个空的ChoiceGroup组件,同时指明其标签和类型。既然该类实现了接口Choice,你可能想到应该有三种选择。但是,在使用一个ChoiceGroup组件时,只有两个选项可用: EXCLUSIVE和MULTIPLE。IMPLICIT类型不适用于ChoiceGroup,就象对于List组件一样。在一个表单中不需要有一个象菜单的选项域(记住EXCLUSIVE方式只允许一次选择一项;MULTIPLE方式则允许一次选择多个项)。
第二个ChoiceGroup构造器用于创建一个新的ChoiceGroup对象,同时指明其标签和类型,还有一个字符串数组和一个图像数组来设置它的初始值。
一旦你创建一个空的选择,你就可以插入,添加或替换其中的选项,就象在一个List组件上一样。而且,每一个选项有一个整数索引值来代表其在列表中的位置。第一个选项从0开始,最后一项索引值是该列表的最大长度减1。ChoiceGroup 类提供了下面方法来完成这些操作。
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); |
注意一个选项由一个字符串和一个可选的图像组成。如,下面代码演示了如何添加几个选项到前述的列表中。注意,方法append( )返回一个索引值(正是我们创建该项时指定给它的),以备后面之用。
int saveIndex = list.append("save", null); int deleteIndex = list.append("delete", null); |
而且,你可以用下面方法从该选项组中删除任何索引:
public void delete(int index); |
如果你想检索任何索引指定的串元素或图像元素,可用下面方法:
public String getString(int index); public Image getImage(int index); |
如果你想设置,取消设置,检索当前选项组中选择的索引,或者查询任何索引以确定它是否为当前选定的项,可以用下面方法:
public int getSelectedIndex( ) public boolean isSelected(int index); public setSelectedIndex(int index, boolean selected); |
最后,就象操作List组件一样,你可以使用一个布尔选项标志数组为设置整个选项组的选择状态。注意,getSelectedFlags( )方法并不返回一个布尔数组,而是修改一个已传入的布尔数组(并作为一种优化技术,返回以整数形式表示的被选取的元素的序号)。该数组的长度至少要等于该列表中元素数目,如果还长一些,其余的数组元素值被置为false。
public int getSelectedFlags(boolean[] selectedArray); public void setSelectedFlags(boolean[] selectedArray); |
对于MULTIPLE型的列表,setSelectedFlags( )用于设置在列表中每个元素的状态。对于EXCLUSIVE型的列表,布尔数组中只有一项可为true;如果没有为true的元素,则第一个元素被选中。如果有两个或者多个元素为true,系统选择第一个为true的元素并选择之。
下面语句创建一个新的空ChoiceGroup对象,其标题为"Selection",类型为EXCLUSIVE:
ChoiceGroup choices = new ChoiceGroup("Method of payment", Choice.EXCLU f22b SIVE); |
下面代码把几个新的选项添加到选择组上。
choices.append("Visa", null); choices.append("Master Card", null); choices.append("Amex", null); |
类似于一个列表中的选项,在一个选项组中的项可以用插入,添加,删除等方法进行编辑。而且,每一个选项被其索引值所参照。如,下面一句可删除最后一项:
特别注意,一旦一个选项组被创建并投入使用,你不可能象操作列表一样,用setCurrent( )方法来显示之。一个选项组是Item的子类,必须放置到表单上去,表单对象是可用方法setCurrent( )显示的。
Form form = new Form("Choose one"); form.append(choices); Display.setCurrent(form); |
图 2展示了一种EXCLUSIVE型的选项组,图3 展示了一种MULTIPLE型的选项组。注意,IMPLICIT值对于ChoiceGroup类是不可用的;如果使用之,将显示一个IllegalArgumentException异常。
图2.一种互斥的选项组 图3.有多个选项的选项组
|
4. DateField
一个DateField对象是一个可编辑的组件,它描述了可以显示在表单对象上的日历中的日期和时间信息。它可以用于显示日期或者时间信息,或者二者皆有。一个DateField对象可以用下面构造器创建:
public DateField(String label, int mode); public DateField(String label, int mode, TimeZone timeZone); |
第一个构造器用于创建有指定的标签和模式的DateField对象。这种模式可以通过提供一个静态字段(DateField.DATE,DateField.TIME或者DateField.DATE_TIME)来指定。DateField.DATE输入模式允许你设置日期信息,DateField.TIME则用于设置时间信息(小时和分钟),DateField.DATE_TIME用于设置日期和时间两种信息。
DateField对象用下列方法来存取加到表单对象上的属性(记住标签属性在抽象类Item 中定义):
public Date getDate( ) public int getInputMode( ) public void setDate(Date date); public void setInputMode(int mode); |
而且,你可以用toString( )方法来输出一个基于字符串的date或者time数据的拷贝。
public String toString( ); |
作为一个例子,下面代码创建一个对象,标签是"Today’s date",方式为DateField.DATE:
DateField date = new DateField("Today’s date", DateField.DATE); |
为了显示一个date域,可先创建一个Form对象,然后使用它的方法append( )添加date域。
Form form = new Form("Date Info"); form.append(date); Display.setCurrent(form); |
在这个例子中,既然选择了DATE输入方式,MIDlet将显示一个<date>项备用户选择,如图4示。一旦选择,它将显示当前的日历日期,你还可以设置一个新的日期。
图 4.一个描述日历上日期的date域
|
如果使用了DateField.TIME输入方式,MIDlet将会显示<time>项备用户选择,如图5示。一旦选择,它将显示当前的时间信息,同样你还可以设置一个新的时间。
图 5.描述时钟上时间信息的date域
|
最后,如果使用了DateField.DATE_TIME输入方式,MIDlet将会显示<date>和<time>项,并允许你做出选择。
注意在显示组件前你可以初始化日期和时间,可以用下面代码来实现:
d = new DateField("Today: ", DateField.DATE); d.setDate(new Date( )); form = new Form("Date & Time"); form.append(d); display.setCurrent(form); |
到此,一个date可以显示当前的date和time,如下图6。
图 6.用DATE_TIME常数描述的日期域的情形
|
第二个DateField构造器用于创建一个日期域,同时指定它的标签,输入模式,和时间带信息.如,下面代码创建一个DateField对象,其时间带是GMT:
DateField date = new DateField("date", DateField.DATE, TimeZone.getTimeZone("GMT")); |
如果TimeZone域取值null,则使用缺省的时间带(基于应用程序运行的时间带)。因而,下列两行代码作用一样:
DateField date1 = new DateField("date", DateField.DATE); DateField date2 = new DateField("date", DateField.DATE, TimeZone.getDefault( )); |
TimeZone类是包java.util中的一部分,该包继承自J2SE。
5. Gauge
一个Gauge对象描述了一个可以使用在表单中的条形图。Gauge类的构造器如下:
public Gauge(String label, boolean interactive, int maxValue, int initialValue); |
该构造器用于创建一新的Gauge对象,并给出标签,以交互或非交互方式,限定最大值并给出初始值。在交互方式下,允许用户修改Gauge的当前值;而在非交互方式下,不允许用户修改Gauge的值(正如你在一个进度条中所见的一样)。你可以用下面方法查询是否当前gauge处于非交互方式:
public boolean isInteractive( ); |
Gauge对象还提供下列方法以存取它的当前值和最大值属性:
public int getMaxValue( ); public int getValue( ); public void setMaxValue(int maxValue); public void setValue(int value); |
Gauge对象将总是维持一个在零和指定的最大值之间的当前值。例如,下面的代码创建一个其最大值是20,初始值为0的交互式的gauge:
Gauge gauge = new Gauge("graph", true, 20, 0); |
一旦创建Gauge 对象,就可以把它放到表单上去:
Form form = new Form("item"); form.append(gauge); |
这个交互的gauge显示在图7中。注意gauge的样式是一个从右向左递增的弧形,正如你在一个LED volume控件所看到的。
图 7.一个交互式gauge的例子
|
如果该gauge用于反映进度,应用程序将保持更新它。在这种情况下,应用程序需要保持一个对它的参照并不断地调用方法setValue( )以反映最新的进度。
下面代码显示出一个非交互的gauge的例子,它反映了一个进度条:
Display display = Display.getDisplay(this); Gauge progressbar = new Gauge("Progress", false, 20, 9); Form form = new Form("Configuring App); form.append(progressbar); |
进度条被显示在图8中。注意在此一个非交互的是从右到左水平方向的。
图 8.一个非交互的gauge,描述了一个进度条
|
6. Image和ImageItem
一个ImageItem对象是图像组件,它包含到一Image对象的参考。首先,简短让我们介绍一下Image类。当我们谈论关于低低API时,将再分析它。
Image类用于图形图像数据的容器。依赖于图像产生的方式,它们可以是不可改变的或者可改变的。不可改变的图像通常是通过从绑定的资源中装入数据或者文件中或者通过网络的方式创建的。一旦他们被创造,他们不能被修改。另一方面,可改变的图像在脱屏内存中创建,可以被修改。
放置于Alert,Form或ImageItem中的图像必须是,既然系统要在不通知应用程序的情况下使用它们来更新显示。另一方面,包含图像的Alert或者Form在每一次图形调用时必须被更新。
一可变的图像能被通过使用Image类的静态方法createImage( )创建。
public static Image createImage(int width, int height); |
其它三个静态的createImage()方法用来创建不可改变的图像:
public static Image createImage(Image image); public static Image createImage(String name); public static Image createImage(byte[] imageData, int imageOffset, int imageLength); |
下面的例子生成一幅源于图形文件的不可改变的图像:
Image image = Image.createImage("/Duke.png"); |
这样,该图像即可image以典型的方式放置到表单上去:
Form form = new Form("Duke"); form.append(image); |
注意图形文件有扩展名png。这个缩略词代表便携式计算机网络图形。所有的MIDP实现均要求支持至少1.0版本的PNG图象。在该文中,没有讨论另外的图形格式化。另外,如果你在使用J2ME无线开发包的Ktoolbar应用程序提供的仿真器,注意对Duke的引用,使用了/duke.png,这意味着Duke在res目录c:/j2mewtk/apps/Myproject/res下。图 9描述了这个例子的结果。
图9.放置一个图像到表单上去
|
图像类提供一些方法用于返回图像的高度,宽度和可变状态:
public int getHeight( ); public int getWidth( ); public boolean isMutable( ); |
另外,如果图像是可变的,你可以使用下面方法取得图像的Graphics对象(当我们讨论低级图形API时,将更详细地讨论它)。
public Graphics getGraphics( ); |
现在,让我们看怎么使用ImageItem类,当Image对象被加到一个form或者alert上时该类用于控制并进行布局。为了创建一ImageItem对象,可以使用ImageItem 构造器:
public ImageItem(String label, Image img, int layout,String altText); |
这个构造器被用于创建一个新的不可改变的ImageItem对象,同时指定一个标签,图像,布局指示及一个可选择的文本串。The altText参数指定用一个字符串来取代显示图像,如果它超过了显示屏的最大容量的话。layout参数 是下面值的一个组合,它们是ImageItem 类的静态字段成员:
ImageItem.LAYOUT_CENTER 图像应该放到水平中央位置
ImageItem.LAYOUT_DEFAULT 应该使用图像容器的默认格式化
ImageItem.LAYOUT_LEFT 图像应该放到绘制区域的左边缘
ImageItem.LAYOUT_NEWLINE_AFTER 在图像被绘制后应开始新的一行
ImageItem.LAYOUT_NEWLINE_BEFORE 在图像被绘制前应开始新的一行
ImageItem.LAYOUT_RIGHT 图像应该放到绘制区域的右边缘
关于如何组合使用上面的值有一些规则:
·ImageItem.LAYOUT_DEFAULT不能与任何其它指令相结合。
·ImageItem.LAYOUT_LEFT, ImageItem.LAYOUT_RIGHT和ImageItem.LAYOUT_CENTER是互相独占的。
·你能用ImageItem.LAYOUT_NEWLINE_AFTER和ImageItem.LAYOUT_NEWLINE_BEFORE结合ImageItem.LAYOUT_LEFT, ImageItem.LAYOUT_RIGHT和ImageItem.LAYOUT_CENTER。
提示:布局指示仅作为一种提示,但是它可以被系统所忽略。Sun的MIDP参考实现就是如此。
ImageItem 类也包含下列方法来存取刚才我们在构造器中看到的属性:
public String getAltText( ); public Image getImage( ); public int getLayout( ); public void setAltText(String altText); public void setImage(Image img); public void setLayout(int layout); |
因此,为了创建一个ImageItem对象,你可以使用上面的ImageItem:
Image img = Image.createImage("/Duke.png"); ImageItem imageItem = new ImageItem("Image", img, ImageItem.LAYOUT_CENTER, "img"); Form form = new Form("Duke"); form.append(imageItem); |
该例子产生一个很类似于图18的结果,除了这里的ImageItem 对象有一个标题。
7. StringItem
一个StringItem对象是一个文本组件,但是它包含的文本串不能被用户编辑。不过一个StringItem可以有一个被应用程序修改的标签,而且StringItem的内容也可以被应用程序编辑。下面是它的构造器:
public StringItem(String label, String contents); |
你可以容易地产生一个StringItem对象:
StringItem si = new StringItem("label", "contents"); |
setText()和getText( )方法用于设置和获取StringItem的内容;setLabel()和getLabel( )方法在抽象类Item中定义,,用于设置和获取StringItem的标签:
public void setText(String s); public void setLabel(String l); public String getText( ); public String getLabel( ); |
下面代码创建一个StringItem 对象并把它放置于一个表单中。之后,该表单被置为当前screen,如图10所示。
图 10.用户不能编辑一个StringItem对象的内容
|
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); |
8. TextField
不象StringItem,一个TextField对象是一个可编辑的文本对象,它可以放置到表单上去。但是,同TextBox一样,一个TextField有最大长度限制(存在该对象中的最大字符数)。同样,MIDP系统部分可以在最大尺寸上限定一个边界值,这可能比应用程序要求的要小。系统指定的最大值可以用方法getMaxSize()检索到。但是,如前所述,在Sun公司的MIDP参考实现部分,方法getMaxSize( )返回应用程序所要求的尺寸。
在你的MIDlet 程序需要用户输入信息时可以使用TextField对象。一个TextField对象可以以TextField类实例的形式创建,看下面的类构造器:
public TextField(String label, String text, int maxSize, int constraints); |
该可以用于创建一个新的TextField对象,在此要指定标签,初始化内容,最大字符数及constraints值。Constraints字段用于限制用户的输入。字段constraints是TextField的静态常数,它们被与TextBox一起共享使用,其值是:TextField.ANY,TextField.EMAILADDR,TextField.NUMBER,TextField.PASSWD,TextField.PHONENUMBER和TextField.URL。记住,如果你使用constraint的值不是TextField.ANY,TextField将执行一个简单的检验来确保输入的字符都是所要求的类型。
如果你想设置或者检索当前正使用TextField的constraints值,可以用下面的方法:
public int getConstraints( ); public void setConstrants(int c); |
MIDP系统指定的最大尺寸可以用方法getMaxSize( )检索到,并可以用setMaxSize( )来重置。
public int getMaxSize( ); public void setMaxSize(int size); |
你可以用方法 setString( )或getString( )来设置或者检索TextField中所有的文本内容:
public String getString( ); public void setString(String s); |
另外,如果你想查看当前输入的字符数,可以用size( )方法,它返回一个整数值:
用来删除,插入和替换当前文本的方法同TextBox:
public void delete(int offset, int length); public void insert(char[] data, int offset, int length, int position); public void insert(String src, int position); public void setChars(char[] data, int offset, int length); |
最后,如果你想找到插入点的位置,可以用下面方法:
public int getCaretPosition( ); |
下面代码显示该组件的作用。它用两个文本域(一个对应登录ID,一个对应口令字)创建一个登录表单。程序运行后,你就可以输入你的用户名和口令,如图11.
图 11.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); |