J2ME手机游戏设计与开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.5 Form类及其组件

3.5.1 Form类介绍

TextBox、List、Alert类只能实现单一的功能,手机屏幕在某一时刻只能显示一个对象,所以很多时候无法满足人们对界面的设计,例如,【例3-5】中为了实现用户名和密码的校验不得不切换界面,如果可以在一个界面中同时输入用户名和密码就会使程序和界面都简化很多,Form类的提出很大程度上解决了这个问题。Form为屏幕表单类,本身是高级屏幕类Screen的子类,可以作为setCurrent()方法的参数直接被使用,但是Form中并没有提供与用户进行交互的界面,它是通过在其中添加其他组件完成交互的,所添加的组件即是Item的子类,包括文本域、日期域、进度条等共计8种。首先介绍Form类本身所提供的常用方法,如表3-11所示。

表3-11 Form类的常用方法

创建并使用Form对象:

Display display;
Form mainForm;
display=Display.getDisplay(this);
mainForm=new Form("屏幕表单及其组件");
display.setCurrent(mainForm);

执行效果如图3-14所示。

3.5.2 StringItem字符串显示类

StringItem类是包含一个字符串的表单组件,只用做显示而不能编辑内容,但通过程序代码可以更改它的标签和文本内容。StringItem类的常用方法如表3-12所示。

表3-12 StringItem类的常用方法

创建并使用StringItem对象:

StringItem si1=new StringItem("StringItem组件","显示字符串信息");
mainForm.append(si1);

执行效果如图3-15所示。

图3-14 Form屏幕表单效果图

图3-15 StringItem组件效果

StringItem类有两个构造函数,第2个构造函数需要3个参数,除了标题和内容外还要给出外观模式,在StringItem中一共定义了3种外观模式。

Item.PLAIN:值为0,无特殊模式。

Item.HYPERLINK:值为1,显示为超级链接。

Item.BUTTON:值为2,显示为按钮。

【例3-8】 添加和修改StringItem对象。

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class mainMidlet extends MIDlet implements CommandListener {
    Display disp;
    Form form;
    StringItem si;
    Command cmd;
    public mainMidlet() {
        disp=Display.getDisplay(this);
        form=new Form("StringItem实例");
        si=new StringItem("内容:","修改前");
        cmd=new Command("修改文本",Command.OK,1);
        form.append(si);
        form.addCommand(cmd);
        form.setCommandListener(this);
    }
    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
    }
    protected void pauseApp() {
    }
    protected void startApp() throws MIDletStateChangeException {
    disp.setCurrent(form);
    }
    public void commandAction(Command arg0, Displayable arg1) {
        if(cmd==arg0)
        {
             si.setText("修改后");
        }
    }
}

执行效果如图3-16所示。

图3-16 StringItem实例效果图

3.5.3 ImageItem图像显示类

ImageItem类能够在Form中显示图片,从而实现比较丰富而复杂的显示界面,其常用方法如表3-13所示。

表3-13 ImageItem类的常用方法

创建和使用ImageItem对象,要想创建ImageItem,首先需要创建Image对象。代码格式为Image img=Image.createImage(“/xm.png”);其中参数为图像的路径。导入图像时要做异常处理,具体代码如下:

Image img;
try {
      img=Image.createImage("/xm.png");
    } catch (Exception e) {
    }
ImageItem ii=new ImageItem("图像",img,ImageItem.LAYOUT_CENTER,"文本");
mainForm.append(ii);

执行效果如图3-17所示。

图3-17 ImageItem 组件效果

构造函数中的第3个参数为ImageItem的布局样式,ImageItem中共定义了6种布局样式。

ImageItem.LAYOUT_DEFAULT:值为0,使用系统默认的图像布局。

ImageItem.LAYOUT_LEFT:值为1,图像靠近绘图区域的左边缘。

ImageItem.LAYOUT_RIGHT:值为2,图像靠近绘图边缘的右边缘。

ImageItem.LAYOUT_CENTER:值为3,图像位于绘图区域的水平中间。

ImageItem.LAYOUT_NEWLINE_BEFORE:值为4,绘制图像前开始新的一行。

ImageItem.LAYOUT_NEWLINE_AFTER:值为5,绘制图像后开始新的一行。

【例3-9】 ImageItem实例。

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class ImageItemTest extends MIDlet {
    Display disp;
    Form form;
    ImageItem ii1,ii2,ii3;
    Image img;
     public ImageItemTest() {
         disp=Display.getDisplay(this);
         form=new Form("ImageItem实例");
         try {
         img=Image.createImage("/_ack_8.png");
         } catch (Exception e) {
         }
         ii1=new ImageItem("左对齐",img,ImageItem.LAYOUT_LEFT,"");
         ii2=new ImageItem("居中对齐",img,ImageItem.LAYOUT_CENTER,"");
         ii3=new ImageItem("右对齐",img,ImageItem.LAYOUT_RIGHT,"");
         form.append(ii1);
         form.append(ii2);
         form.append(ii3);
     }
     protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
     }
     protected void pauseApp() {
     }
     protected void startApp() throws MIDletStateChangeException {
         disp.setCurrent(form);
     }
}

执行效果如图3-18所示。

图3-18 ImageItem实例效果图

3.5.4 TextField文本域类

TextField为文本域类,主要用来输入和显示文本内容,TextField类的常用方法如表3-14所示。

表3-14 TextField类的常用方法

创建并使用TextField对象:

TextField tf=new TextField ("任意字符", "初始字符",20,TextField.ANY);

TextField的构造函数与TextBox非常类似,第1个参数是标签文本,第2参数是初始时显示的字符,第3个参数是能够容纳的最大字符数,最后一个参数是输入的文本约束。

TextField和TextBox的区别是前者是Item的子类,不能直接被setCurrent方法调用,只能被添加到Form上才能被显示在手机屏幕上,后者则是Screen类的子类,可以直接被setCurrent()方法调用显示,但是某一时刻只可以显示一个TextBox对象。

这里首先利用TextField对象的特点修改一下【例3-5】,修改后的结果参见【例3-10】。

【例3-10】 TextField的用户名和密码验证。

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class mainMidlet extends MIDlet implements CommandListener {
    Display display;
    Form form;
    TextField tfName,tfPwd;
    StringItem si;
     Command cmdEnter;
    public mainMidlet() {
        display=Display.getDisplay(this);
        form=new Form("登录界面");
        tfName=new TextField("请输入用户名","",12,TextField.ANY);
        tfPwd=new TextField("请输入密码","",6,TextField.NUMERIC);
        cmdEnter=new Command("确定",Command.OK,1);
        si=new StringItem("","");
        form.append(tfName);
        form.append(tfPwd);
        form.addCommand(cmdEnter);
        form.setCommandListener(this);
    }
    protected void destroyApp(boolean arg0)throws MIDletStateChangeException{ }
    protected void pauseApp() { }
    protected void startApp() throws MIDletStateChangeException {
        display.setCurrent(form);
    }
    public void commandAction(Command c, Displayable d) {
        if(c==cmdEnter )
        {
             if(tfName.getString().equals("abc")&&tfPwd.getString(). equals("123"))
                 si.setText("输入正确");
             else
                 si.setText("输入错误");
             form.deleteAll();
             form.append(si);
        }
    }
}

执行效果如图3-19所示。

图3-19 TextField用户名和密码验证效果图

3.5.5 DateField日期域类

DateField为日期域类,主要用来输入和显示日期和时间。DateField类的常用方法如表3-15所示。

表3-15 DateField类的常用方法

创建并使用DateField对象:

DateField df=new DateField("出生日期", DateField.DATE);

DateField有两个构造函数,第1个构造函数DateField(String label,int mode)使用指定的标签和输入模式来构建DateField对象,第2个构造函数DateField(String label,int mode,TimeZone timeZone)则需要在指定标签和输入模式的同时还指定时区,如果TimeZone的值为null,则使用系统默认时区。

DateField类中共定义了3种输入模式:DateField.DATE(日期)、DateField.TIME(时间)和DateField.DATE_TIME(日期加时间)。

构造完成后,DateField还处于未初始化状态,没有具体的日期时间,可以使用setDate(Date date)方法为其设置初始值。

将DateField对象添加到Form对象中:

mainForm.append(df);

执行效果如图3-20所示。

图3-20 DateField对象效果

下面运用DateField类来看看不同的输入模式的表现有何不同,具体实现参见【例3-11】。

【例3-11】 DateField类的不同输入模式。

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.Date;
public class DateFieldTest extends MIDlet implements CommandListener{
    private Form form;
    private List startmenu;
    private long date, time;
    //计算一天有多少毫秒
    private long dayInMillis=24*60*60*1000;
    private String choices[]={"DATE mode","TIME mode", "DATE_TIME mode"};
    private Command backCommand = new Command("Back", Command.BACK, 1);
    private Command okCommand = new Command("OK", Command.OK, 1);
    private Command exitCommand = new Command("EXIT", Command.EXIT, 1);
    private Display display;
    public DateFieldTest() {
       //创建List对象作为起始菜单
    startmenu= new List("Chooise a input mode",List.IMPLICIT,choices,null);
    startmenu.addCommand(exitCommand);
    startmenu.setCommandListener(this);
       //创建Form对象
       form= new Form("DateField Test");
       DateField df=new DateField("",DateField.DATE_TIME);
       //System.currentTimeMillis()表示系统的当前时间
       time=System.currentTimeMillis()%dayInMillis;
       date=System.currentTimeMillis()-time;
       df.setDate(new Date(date+time));
       form.append(df);
       form.addCommand(okCommand);
       form.addCommand(backCommand);
       form.setCommandListener(this);
       display=Display.getDisplay(this);
    }
    public void startApp() throws MIDletStateChangeException {
        display.setCurrent(startmenu);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
       form=null;
       startmenu=null;
       backCommand = null;
       okCommand=null;
       exitCommand = null;
       display=null;
    }
    public void commandAction(Command c, Displayable d) {
       if(d==startmenu && c==List.SELECT_COMMAND) {
           //form.get(0)表示获取form界面中的第一个组件
           DateField df= (DateField) form.get(0);
           //保存设置的日期或时间
           if(df.getInputMode()==DateField.DATE) {
               date=df.getDate().getTime();
           }
           else if(df.getInputMode() == DateField.TIME) {
               time=df.getDate().getTime();
           }
           else {
               time=df.getDate().getTime()%dayInMillis;
               date=df.getDate().getTime()-time;
           }
           //设置时间和输入模式
           df.setLabel(choices[startmenu.getSelectedIndex()]);
           switch(startmenu.getSelectedIndex()) {
           case 0:
               df.setInputMode(DateField.DATE);
               df.setDate(new Date(date));
               break;
           case 1:
               df.setInputMode(DateField.TIME);
               df.setDate(new Date(time));
               break;
           case 2:
               df.setInputMode(DateField.DATE_TIME);
               df.setDate(new Date(date+time));
               break;
           }
           display.setCurrent(form);
       }
       else if(d==form && c==okCommand) {
           DateField df= (DateField) form.get(0);
       System.out.println("Time set in millis: "+df.getDate().getTime());
         }
         else if(c==backCommand) {
             display.setCurrent(startmenu);
         }
         else if(c==exitCommand) {
             destroyApp(true);
             notifyDestroyed();
         }
    }
}

执行效果如图3-21所示。

图3-21 DateField类的不同输入模式效果

3.5.6 Gauge类图形标尺

Gauge类实现了一个图像标尺,通常被用来表示一个过程的进展情况,例如进度条、音量调节界面等。Gauge类的常用方法如表3-16所示。

表3-16 Gauge类的常用方法

创建并使用Gauge对象:

Gauge gauge=new Gauge("图形标尺",true,5,0);

Gauge只有一个构造方法,其中第1个参数为图形标尺的标签,可以设置为null,第2个参数表示是否允许用户交互,第3个参数表示标尺的最大值,必须大于0,第4个参数表示标尺的初始值。

将Gauge对象添加到Form界面中:

gauge.setLayout(Item.LAYOUT_CENTER);//设置布局模式居中
mainForm.append(gauge);

如果是否允许交互值为true,则执行效果如图3-22(a)所示;如果为false,则效果如图3-22(b)所示。

图3-22 Gauge对象效果

Gauge类的完整实例程序参见【例3-12】。

【例3-12】 Gauge类对象的应用。

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class GaugeTest extends MIDlet implements CommandListener{
    private Form form;
    private List startmenu;
    private String choices[]={"Interactive Gauge","Non-interactive Gauge"};
    private Command backCommand = new Command("Back", Command.BACK, 1);
    private Command exitCommand = new Command("EXIT", Command.EXIT, 1);
    private Display display;
    public GaugeTest() {
    startmenu= new List("Chooise a Gauge type",List.IMPLICIT,choices,null);
    startmenu.addCommand(exitCommand);
    startmenu.setCommandListener(this);
        form= new Form("Gauge Test");
        form.addCommand(backCommand);
        form.setCommandListener(this);
        display=Display.getDisplay(this);
    }
    public void startApp() throws MIDletStateChangeException {
        display.setCurrent(startmenu);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
        form=null;
        startmenu=null;
        backCommand = null;
        exitCommand = null;
        display=null;
    }
    public void commandAction(Command c, Displayable d) {
        if(d==startmenu && c==List.SELECT_COMMAND) {
            if(form.size()>0) form.delete(0);
            if(startmenu.getSelectedIndex()==0) {
               form.append(new Gauge("Interactive Gauge",true,10,4));
            }
            else {
            form.append(new Gauge("Non-interactive Gauge",false,10,4));
            }
            display.setCurrent(form);
    }
        else if(c==backCommand) {
            display.setCurrent(startmenu);
        }
        else if(c==exitCommand) {
            destroyApp(true);
            notifyDestroyed();
        }
    }
}

执行效果如图3-23所示。

图3-23 Gauge中的交互模式和非交互模式效果图

3.5.7 Spacer类

Spacer类是MIDP 2.0中特有的不可见组件,通常是提供其他组件之间的垂直和水平间隔,用于定位。Spacer类的常用方法如表3-17所示。

表3-17 Spacer类的常用方法

创建和使用Spacer对象:

Spacer sp=new Spacer(30,30);
mainForm.append(sp);

效果如图3-24所示,其中(a)为未使用Spacer组件效果,(b)为使用Spacer组件效果。

图3-24 Spacer对象效果

3.5.8 CustomItem类自定义组件

已有的高级屏幕类组件并不能满足开发者对界面的要求,所以在MIDP 2.0中引入了CustomItem自定义组件类实现像素级别的绘制和内部事件的处理。

CustomItem类为抽象类,在实际运用时需要派生一个CustomItem的子类,在子类中通过实现CustomItem的抽象方法及定义自己的方法来完善实际的功能,从而绘制较复杂的画面,这些与普通的Item类略有不同。CustomItem类的常用方法如表3-18所示。

表3-18 CustomItem类的常用方法

CustomItem的功能介于高级和低级之间的用户界面,它既可以添加到Form中,也可以扩展为图像用户界面,通过实现一系列抽象方来绘制具体的图形。实现自定义界面的代码参见【例3-13】。

【例3-13】 利用CustomItem类绘制自定义表格。

(1)建立MIDlet类。

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class CustomMidlet extends MIDlet {
     Display display;
     Form mainForm;
     MyCustomItem custom;
    public CustomMidlet() {
        display=Display.getDisplay(this);
        mainForm=new Form("自定义组件");
        custom=new MyCustomItem("表格");
        mainForm.append(custom);
    }
    protected void destroyApp(boolean arg0) throws MIDletStateChange Exception { }
    protected void pauseApp() { }
    protected void startApp() throws MIDletStateChangeException {
        display.setCurrent(mainForm);
    }
}

(2)MyCustomItem类的基本框架。

import javax.microedition.lcdui.*;
public class MyCustomItem extends CustomItem {
    public MyCustomItem(String label) {
        super(label);
    }
    protected int getMinContentHeight() {
        return 0;
    }
    protected int getMinContentWidth() {
        return 0;
    }
    protected int getPrefContentHeight(int arg0) {
        return 200;
    }
    protected int getPrefContentWidth(int arg0) {
        return 200;
    }
    protected void paint(Graphics arg0, int arg1, int arg2) {
        for(int i=0;i<=5;i++)
        { arg0.drawLine(0, i*20, 100, i*20);
          arg0.drawLine(i*20, 0, i*20, 100);
        }
    }
}

(3)执行效果如图3-25所示。

图3-25 自定义表格效果