目 录

StringItem对象和TextField、DateField对象类似,同样属于项目类型的对象。它的作用就是在容器对象中显示一条字符串。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ShowStringItem extends MIDlet implements CommandListener {
private Display display;


private Form props;
private StringItem strItem;
private StringItem strItem2;

private Command exitCommand = new Command("Exit", Command.EXIT, 1);

public ShowStringItem() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
props.append("Hello World! ");
strItem = new StringItem("signature:", "小楼一夜听春雨");
strItem2 = new StringItem("signature:", "三教明天考物化");

props.append(strItem);
props.append(strItem2);
props.addCommand(exitCommand);
props.setCommandListener(this);

display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

ImageItem对象是一个项目类型的对象,他的作用是在容器中显示图片。那么如何使用ImageItem对象呢?请按照下面三个步骤进行:

1.构造一个Image对象,相关代码如下所示:

Image img=Image.createImage("/fancy/test/JavaPowered-8.png");

createImage()方法是Image类的静态方法,它的作用是根据图形文件创建一个Image对象。
J2ME程序中所用到的图片文件必须存放在appsfancy es文件夹下面。

2.构造ImageItem对象,相关代码如下所示:
imgItem=new ImageItem("Default Layout",img,ImageItem.LAYOUT_DEFAULT,
"Image Cannot be shown");
ImageItem类的构造函数有三个参数,第一个参数的作用是显示一个标签,第二个参数指明图片的对齐方式,第三个参数的作用是显示图片的tip。

3.利用容器类对象的append()方法将ImageItem对象添加进去。如:
props.append(imgItem);
下面我们来看一个比较完整的例子。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ShowImageItem extends MIDlet implements CommandListener {
private Display display;
private Form props;
private Image img;
private ImageItem imgItem;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public ShowImageItem() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
// props.append("Hello World! ");
try {
img = Image.createImage("/fancy/test/JavaPowered-8.png");
imgItem = new ImageItem("Default Layout",
img, ImageItem.LAYOUT_DEFAULT,
"Image Cannot be shown ");
props.append(imgItem);
props.append(new ImageItem("Left Layout",
img, ImageItem.LAYOUT_LEFT,
"Image Cannot be shown "));
props.append(new ImageItem("Center Layout",
img, ImageItem.LAYOUT_CENTER,
"Image Cannot be shown "));
} catch (Exception fe) {
// to do nothing
}
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

ChoiceGroup也是一个项目类型的对象,它代表一个选择列表,它的作用和List对象类似,不过后者是一个容器,而前者是一个项目。
我们需要特别注意ChoiceGroup类的构造函数,它有四个参数,第一个参数是标签,第二个参数是此选择列表的类型,例如多选还是单选。第三个参数是 一个字符串数组,代表每个选项的标签,第四个选项是一个Image类型的数组,代表每个选项前面的小图标。下面是一个比较完整的例子。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ShowChoiceGroup extends MIDlet implements CommandListener {
private Display display;
private Form props;

private Image duke;
private Image[] imageArray;
private ChoiceGroup choice;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public ShowChoiceGroup() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
// props.append("Hello World! ");
try {
Image duke = Image.createImage("/fancy/test/Icon.png");
imageArray = new Image[] {duke, duke, duke};
String[] stringArray = {"Option A", "Option B", "Option C"};
choice = new ChoiceGroup("choice group", ChoiceGroup.MULTIPLE,
stringArray, imageArray);
props.append(choice);
} catch (Exception fe) {
// to do nothing.
}
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}

public void destroyApp(boolean unconditional)

{
}
public void pauseApp() {
display.setCurrent(null);
props = null;
}
}
}


Gauge对象是一个项目类型的对象,它的作用是显示一个进度条。请看下面的源代码。
Gauge类的构造函数的后面两个参数分别是进度条的最大值和初始值。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ShowGauge extends MIDlet implements CommandListener {
private Display display;
private Form props;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public ShowGauge() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
// props.append("Hello World! ");
Gauge gauge = new Gauge("show gauge", true, 100, 50);
props.append(gauge);
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

Ticker对象是一个项目类型的对象,它的作用相当于一个滚动消息栏,在屏幕的上方显示滚动的信息。 Ticker类的构造函数仅有一个参数,那就是需要滚动显示的消息。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ShowTicker extends MIDlet implements CommandListener {
private Display display;
private Form props;

private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public ShowTicker() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");

props.append("Hello World! ");
Ticker ticker = new Ticker("ticker");
props.setTicker(ticker);
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

在前面的例子中,我们已经演示了如何构造J2ME程序的用户界面。现在有一个问题,那就是如何与用户界面交互呢?亦即如何获取用户通过用户界面输入 的值呢?请看下面的例子。

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class GetTextBoxvalue extends MIDlet implements CommandListener {
private Display display;
private TextBox txtBox;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
private Command getCommand = new Command("GETvalue", Command.OK, 1);
public GetTextBoxvalue() {
display = Display.getDisplay(this);
}

public void startApp() {
// or :
// String str="hello world";
// txtBox = new TextBox("Text Box",str,str.length(),0);
// the follow code is wrong:
// txtBox = new TextBox("Text Box",str,any number here,0);
txtBox = new TextBox("Text Box", null, 200, 0);
txtBox.addCommand(exitCommand);
txtBox.addCommand(getCommand);
txtBox.setCommandListener(this);
display.setCurrent(txtBox);
}

public void valueScreen() {
Form props = new Form("get text box value");
props.append(txtBox.getString());
props.addCommand(exitCommand);
props.setCommandListener(this);

display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
if (c == getCommand) {
valueScreen();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {

display.setCurrent(null);
txtBox = null;
}
}

在上面的例子中(GetTextBoxvalue.java),当我们往文本框中输入文本,并按下退出按钮,接着选择GETvalue命令的时候, 将会调用valueScreen()方法。valueScreen()方法的源代码如下:

public void valueScreen() {
    Form props=new Form("get text box value");
    props.append(txtBox.getString());
    props.addCommand(exitCommand);
    props.setCommandListener(this);
    display.setCurrent(props);
}

valueScreen()方法的逻辑是:首先创建一个容器对象Form,然后调用TextBox对象的getString()方法,获取文本框中 的输入值,追加到容器对象中,最后将此Form对象作为屏幕的当前显示对象。

Date对象是属于java.util包的,它的作用是返回当前的时间。请看下面的代码:

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

import java.util.*;

public class GetDate extends MIDlet implements CommandListener {
private Display display;
private Form props;
private Date date;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public GetDate() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
props.append("Hello World! ");
date = new Date();
props.append("Now Time:" + date.getTime() + " ");

props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;

}
}

TimeZone对象也是属于java.util包的。这个对象的作用是提供关于时区的信息。TimeZone类有一个静态方法 ----getDefault(),可以获取与当前系统相关的时区对象。getAvailableIDs()方法可以获取系统中所有可用的时区的ID 号,getID()方法可以获取系统当前所设置的时区。具体的例子如下所示

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class GetTimeZone extends MIDlet implements CommandListener {
private Display display;
private Form props;
// private Date date;
private TimeZone zone;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public GetTimeZone() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
props.append("Hello World! ");
// date=new Date();
// props.append("Now Time:"+date.getTime()+" ");
zone = TimeZone.getDefault();
String[] zoneid = zone.getAvailableIDs();
for (int i = 0; i < zoneid.length; i++) {
props.append(zoneid[i] + " ");
}
props.append("Current Time Zone:" + zone.getID() + " ");
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {

destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

Calendar对象归属于java.util包,它可以提供更为详尽的时间信息。具体的例子如下所示

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

public class GetCalendar extends MIDlet implements CommandListener {
private Display display;
private Form props;
// private Date date;
// private TimeZone zone;
// private Calendar calendar;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public GetCalendar() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Hello World");
props.append("Hello World! ");
Calendar rightNow = Calendar.getInstance();
props.append("YEAR:" + rightNow.get(Calendar.YEAR) + " ");
props.append("MONTH:" + rightNow.get(Calendar.MONTH) + " ");
props.append("DAY OF MONTH:"
+ rightNow.get(Calendar.DAY_OF_MONTH) + " ");
props.append("HOUR OF DAY:"
+ rightNow.get(Calendar.HOUR_OF_DAY) + " ");
props.append("MINUTE:"
+ rightNow.get(Calendar.MINUTE) + " ");
props.append("SECOND:"
+ rightNow.get(Calendar.SECOND) + " ");
props.append("MILLISECOND:"
+ rightNow.get(Calendar.MILLISECOND) + " ");
// date=new Date();
// props.append("Now Time:"+date.getTime()+" ");
// zone=TimeZone.getDefault();
// String []zoneid=zone.getAvailableIDs();
// for(int i=0;i

在J2ME程序中,可以利用HttpConnection接口建立HTTP连接,访问远程服务器上的资源。具体的代码如下所示:

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;

public class GetHttpConnection extends MIDlet implements CommandListener {
private Display display;
private Form props;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public GetHttpConnection() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Get Http Connection");
// props.append("Hello World! ");
try {
HttpConnection conn = (HttpConnection) Connector.open
("http://rainbow:8080/index.html"; );
// conn.setRequestProperty("user","fancy");
props.append("Date:" + conn.getDate() + " ");
props.append("Expiration:" +
conn.getExpiration() + " ");
props.append(conn.getHost() + " ");
props.append("Last Modified:" +
conn.getLastModified() + " ");
props.append("Port:" + conn.getPort() + " ");
props.append("Protocol:" +
conn.getProtocol() + " ");
props.append("Request Method:" +
conn.getRequestMethod() + " ");
props.append("Response Code:" +
conn.getResponseCode() + " ");
props.append("Encoding:" +
conn.getEncoding() + " ");
props.append("Length:" + conn.getLength() + " ");
props.append("Type:" + conn.getType() + " ");
props.append("URL:" + conn.getURL() + " ");
props.append("Response Message:" +
conn.getResponseMessage() + " ");
} catch (Exception fe) {
props.append("Error:" + fe.getMessage());
}
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

Connector类提供了open()方法,可以和各种各样的远程资源建立连接。open()方法的参数就是远程资源的URL地址。open() 方法的返回值是一个Connection接口。为了建立HTTP连接,我们应该将它强制转换为HttpConnection接口的形式。一旦获取 HttpConnection接
口的实例对象,就可以调用HttpConnection接口的各种方法,得到关于HTTP连接的各种信息。

我的想法是建立一个Web服务器,使用Tomcat 4.0,支持JSP技术。再配置一个Mail服务器,使用的软件是Imail 7.0.4。首先编写一个可以发送电子邮件的JSP程序(post.jsp),
具体代码
如下所示:
 <%@ page import="java.net.*" %>
<%@ page import="java.io.*" %>
<%@ page import="javax.activation.*" %>
<%@ page import="java.util.*" %>
<%@ page import="javax.mail.*" %>
<%@ page import="javax.mail.internet.*" %>

<%!
public class SmtpAuthenticator extends javax.mail.Authenticator

{
    public javax.mail.PasswordAuthentication
    getPasswordAuthentication()
    {
        return new javax.mail.PasswordAuthentication("fancy",
        "fancy");
    }
}
%>

<%
String username="fancyrainbow";
String password="fancy";
String from="fancy@rainbow";
String to="fancy@rainbow";
String cc="fancy@rainbow";
String subject="J2ME Mail Test";
//String content="J2ME Mail Test";
String content=request.getParameter("content");

Properties props = System.getProperties();
props.put("mail.smtp.auth","true");

props.put("mail.smtp.host","rainbow"); //263

SmtpAuthenticator sa=new SmtpAuthenticator();
Session sess = Session.getInstance(props, sa);
sess.setDebug(true);

Message msg = new MimeMessage(sess);

msg.setFrom(new InternetAddress(from));
msg.setRecipients(Message.RecipientType.TO,InternetAddress.parse(to, false));
msg.addRecipients(Message.RecipientType.CC,InternetAddress.parse(cc, false));
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setText(content);
Transport.send(msg);
%>
Send Message OK!
我将post.jsp程序保存在Tomcat 4.0的ROOT目录下面,然后使用Web浏览器测试此程序成功。然后再将上一个J2ME程序(GetHttpConnection.java)改一改, 让它与Tomcat 4.0
服务器建立连接,请求post.jsp程序。相关代码如下所示:

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;

public class SendMail extends MIDlet implements CommandListener {
private Display display;
private Form props;
private Command exitCommand = new Command("Exit", Command.EXIT, 1);
public SendMail() {
display = Display.getDisplay(this);
}

public void startApp() {
props = new Form("Get Http Connection");
// props.append("Hello World! ");
try {
HttpConnection
conn = (HttpConnection) Connector.open(
"http://rainbow:8080/post.jsp?content=Hello World");
// conn.setRequestProperty("user","fancy");
props.append("Date:" + conn.getDate() + " ");
props.append("Expiration:" + conn.getExpiration() + " ");
props.append(conn.getHost() + " ");
props.append("Last Modified:" + conn.getLastModified() + " ");
props.append("Port:" + conn.getPort() + " ");
props.append("Protocol:" + conn.getProtocol() + " ");
props.append("Request Method:" + conn.getRequestMethod() + " ");
props.append("Response Code:" + conn.getResponseCode() + " ");
props.append("Encoding:" + conn.getEncoding() + " ");
props.append("Length:" + conn.getLength() + " ");
props.append("Type:" + conn.getType() + " ");
props.append("URL:" + conn.getURL() + " ");
props.append("ResponseMessage:" + conn.getResponseMessage() + " ");
// InputStream is=conn.openInputStream();
// DataInputStream dis=new DataInputStream(is);
// props.append("System Info:"+dis.readUTF()+" ");
props.append("Send Mail OK!" + " ");
} catch (Exception fe) {
props.append("Error:" + fe.getMessage());
}
props.addCommand(exitCommand);
props.setCommandListener(this);
display.setCurrent(props);
}

public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}

public void destroyApp(boolean unconditional) {
}

public void pauseApp() {
display.setCurrent(null);
props = null;
}
}

启动Tomcat 4.0、Imail 7.0.4、J2MEWTK。在J2MEWTK中运行SendMail.java程序,事后检查邮箱,发现已经成功的收到了邮件。

有两点需要说明一下:
首先,按照上面的模式,我们可以编写出功能更为强大的程序来,例如使用J2ME+JDBC+JSP访问远程的数据库系统,访问EJB组件等等。

其次,如果要读取post.jsp程序的输出信息,你可以从HttpConnection接口中获取一个输入流对象,逐个读取输入流中的数据即可。具体的 代码我就不举了,你可以参考J2ME的DOC。

终于写完啦!

自从大一接触Java以来,四年了,每天不Java一下就手痒,每天不Java一下就觉得有些失落,Java已经成为我的生活的一个部分。Java给予我 很多的乐趣,我想我应该为Java作些什么。四天前,当我开始接触J2ME,当我使用J2MEWTK成功运行HelloWorld程序的时候,这个念头再 次浮现在我的脑海里。我应该为Java做些自己力所能及的事情,所以才会有这篇不算太长的文章《J2ME学习札记》。不管别人的看法怎么样,我总算是了了 自己的一番心事。我之所以写这篇文章,还有另一个目的,那就是将我从Java中得到乐趣与你分享,希望你也能够将你从Java中获取的乐趣写出来,与大家 分享。

from pku
Ahthor:javalover